//========================================================================
//  SE5 External Events - Captain Kwok's Balance Mod v130+
//========================================================================
//
// Balance Mod Changes:
// --------------------
// v1.29 Added   - Fx[Check_Political_Status] to verify if war status is real or a fake treaty name
//       Added   - Fx[Deplete_Resources_From_Remote_Mining] to deplete resources from remote mined objects in finite resource games
//       Added   - Fx[Execute_Damage_From_Asteroids] as a random event from damage in asteroid fields
//       Fixed   - Events that damaged shield generators had a typo in the damage type name
//       Fixed   - In some cases the damage amount applied to a ship didn't account for the armor hitpoints
//       Added   - Fx[Execute_Event_Plague_Spreading] to consider spreading a plague to an adjacent planet
//       Added   - Fx[Verify_Empire_Scores] as a backup score reference for AI calculations
//       Changed - Allegiance Subverter Amplifier chance fades at distance (50% reduction in chance at target range > subverter level * 5)
//       Added   - Fx[Compute_System_Chokepoint_Scores] to identify critical chokepoint systems as store centrally for the AI to reference
//       Fixed   - The minefield detonation event will now report the exact number of mines destroyed in the accident
// v1.28 Added   - Fx[Execute_Blackhole_Damage] to apply random damage when a ship is in a black hole system
//       Changed - Small increase to event frequency rates + increased chance for certain types of events
// v1.27 Fixed   - The minefield damage event wasn't creating a log message
// v1.26 Fixed   - Smaller planets were not getting the full benefit of the environmental achievement reduction for pollution
//       Changed - The event severity level has been incorporated into the effect amount for select events (planetary events)
// v1.25 Fixed   - Luck was accidentally providing too much luck for research breakthroughs
//       Changed - Made research breakthroughs/setbacks a bit more ambiguous by removing the amount of points gained or lost
//       Changed - Added more variety to the ship damaged event including different types of damage
//       Added   - New Fx[Execute_Dimensional_Rift_Damage] for executing Dimensional Rift Projector damage
//       Added   - New Fx[Execute_Event_Minefield_Damage] that causes damage or potentially detonates an entire minefield
//       Added   - New Fx[Fix_Planet_Names] to correct planet names in certain types of systems
//       Changed - Updated Fx[Execute_Event_Random_Research] to reflect tech area costs in v125+
//       Added   - Pollution conditions change log message will project ending conditions for the planet in question
//       Added   - New Fx[Execute_Subverter_Damage] for executing Allegiance Subverter Amplifier damage
// v1.24 Fixed   - Sometimes the pollution conditions modifier was applied incorrectly on low pollution planets
//       Changed - Pollution effects are reduced for the first 25 turns
// v1.22 Added   - Merged Balance Mod Research Events extension (based on values in ModEventSettings.txt)
//       Added   - Merged Balance Mod Pollution Events extension (based on values in ModEventSettings.txt)
//       Changed - Luck will impact research breakthroughs/setbacks
// v1.21 Changed - Reduced strength of unhappiness penalty as number of war turns increased
// v1.20 Added   - Added happiness modifier for war tolerance in Fx[Population_Events]
// v1.19 Added   - Fx[Population_Events] to allow for populations with low loyalty to decrease happiness (v1.19h)
//       Changed - Change in planet happiness was incorrectly increasing happiness (v1.19h)
//       Fixed   - Damage amounts for planet damage events was incorrect (v1.19i)
// v1.15 Changed - Updated conditions change and value change events to new script functions
//       Fixed   - Damage planet value event was not working correctly
//       Fixed   - Planet happiness event was not working correctly
//       Added   - Random variations on some events
//       Changed - Event frequency rates increase with more players
//       Changed - Increased overall event rates
// v1.12 Fixed   - Ships that rebel will only change over to known empires
//       Fixed   - Only ships with movement will have their orders changed
// v1.10 Added   - Script fixes from SE:v v1.58 patch
// v0.70 Changed - Reduce the effect amount for some events
//
// Balance Mod To-do List:
// -----------------------
// - Nothing pending
//
// Script Function Requests:
// -------------------------
// - Nothing pending

//------------------------------------------------------------------------
// Global Constants
//------------------------------------------------------------------------
globalconst

  BASE_EVENT_RECORD_LENGTH:                        long      := 2
  TIMED_EVENT_RECORD_LENGTH:                       long      := 5

  PARAM_TYPE_SHIP:                                 long      := 1
  PARAM_TYPE_UNITGROUP:                            long      := 2
  PARAM_TYPE_PLANET:                               long      := 3
  PARAM_TYPE_WARP_POINT:                           long      := 4
  PARAM_TYPE_STAR:                                 long      := 5
  PARAM_TYPE_STORM:                                long      := 6
  PARAM_TYPE_SYSTEM:                               long      := 7
  PARAM_TYPE_PLAYER:                               long      := 8
  PARAM_TYPE_BLACK_HOLE:                           long      := 9
  PARAM_TYPE_NEBULAE:                              long      := 10

  EVENT_ID_SHIP_DAMAGE:                            long      := 1
  EVENT_ID_SHIP_LOSE_MOVEMENT:                     long      := 2
  EVENT_ID_SHIP_LOSE_SUPPLIES:                     long      := 3
  EVENT_ID_SHIP_CARGO_DAMAGE:                      long      := 4
  EVENT_ID_SHIP_REBELS:                            long      := 5
  EVENT_ID_SHIP_EXPERIENCE_CHANGE:                 long      := 6
  EVENT_ID_SHIP_ORDERS_CHANGE:                     long      := 7
  EVENT_ID_SHIP_MOVED:                             long      := 8
  EVENT_ID_MINEFIELD_DAMAGE:                       long      := 9
  EVENT_ID_PLANET_CONDITIONS_CHANGE:               long      := 10
  EVENT_ID_PLANET_VALUE_CHANGE:                    long      := 11
  EVENT_ID_PLANET_POPULATION_CHANGE:               long      := 12
  EVENT_ID_PLANET_POPULATION_HAPPINESS_CHANGE:     long      := 13
  EVENT_ID_PLANET_POPULATION_RIOT:                 long      := 14
  EVENT_ID_PLANET_POPULATION_REBEL:                long      := 15
  EVENT_ID_PLANET_CARGO_DAMAGE:                    long      := 16
  EVENT_ID_PLANET_PLAGUE_CREATED:                  long      := 17
  EVENT_ID_PLANET_PLAGUE_CURED:                    long      := 18
  EVENT_ID_PLANET_CREATED:                         long      := 19
  EVENT_ID_PLANET_DESTROYED:                       long      := 20
  EVENT_ID_STAR_CREATED:                           long      := 21
  EVENT_ID_STAR_DESTROYED:                         long      := 22
  EVENT_ID_WARP_POINT_CLOSED:                      long      := 23
  EVENT_ID_WARP_POINT_OPENED:                      long      := 24
  EVENT_ID_STORM_CREATED:                          long      := 25
  EVENT_ID_STORM_DESTROYED:                        long      := 26
  EVENT_ID_NEBULAE_CREATED:                        long      := 27
  EVENT_ID_NEBULAE_DESTROYED:                      long      := 28
  EVENT_ID_BLACK_HOLE_CREATED:                     long      := 29
  EVENT_ID_BLACK_HOLE_DESTROYED:                   long      := 30
  EVENT_ID_EMPIRE_POINTS_CHANGE:                   long      := 31

  EVENT_SEVERITY_LOW:                              long      := 0
  EVENT_SEVERITY_MEDIUM:                           long      := 1
  EVENT_SEVERITY_HIGH:                             long      := 2
  EVENT_SEVERITY_CATASTROPHIC:                     long      := 3

  EVENT_FREQUENCY_NONE:                            long      := 0
  EVENT_FREQUENCY_LOW:                             long      := 1
  EVENT_FREQUENCY_MEDIUM:                          long      := 2
  EVENT_FREQUENCY_HIGH:                            long      := 3

  MESSAGE_TO_NONE:                                 long      := 0
  MESSAGE_TO_OWNER:                                long      := 1
  MESSAGE_TO_SECTOR:                               long      := 2
  MESSAGE_TO_SYSTEM:                               long      := 3
  MESSAGE_TO_ALL:                                  long      := 4

endglobalconst

//------------------------------------------------------------------------
// Global Variables
//------------------------------------------------------------------------
globalvars

  lng_Datafile_Event_Text_ID:                              long := 0
  lng_Event_Frequency:                                     long := 0
  lng_Event_Severity:                                      long := 0
  bool_ModEventSetting_Allow_Research_Events:              boolean := TRUE
  bool_ModEventSetting_Allow_Pollution_Events:             boolean := TRUE
  bool_ModEventSetting_Allow_Plague_Spreading_Events:      boolean := TRUE

endglobalvars

//------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Forward Declarations
//------------------------------------------------------------------------

deffunc

function Compute_System_Chokepoint_Scores returns boolean
params
end

function Verify_Empire_Scores returns boolean
params
end

function Fix_Planet_Names returns boolean
params
end

function Check_Political_Status returns boolean
params
end

function Population_Events returns boolean
params
end

function Deplete_Resources_From_Remote_Mining returns boolean
params
end

function Execute_Damage_From_Asteroids returns boolean
params
end

function External_Events returns boolean
params
end

function Select_Event returns long
params
  event_severity:            long
end

function Execute_Event returns boolean
params
  event_id:                  long
end

function Select_Event_Parameter returns long
params
  param_type:                long
end

function Is_Target_Param_Acceptable returns boolean
params
  param_type:                long
  param_id:                  long
end

function Give_Message_To_Players returns boolean
params
  msg_to_type:               long
  to_plr:                    long
  sys_loc:                   long
  sect_loc:                  long
  msg_title:                 string
  msg_text:                  string
  small_portrait_pic:        string
  large_portrait_pic:        string
  log_type:                  long
end

function Execute_Event_Ship_Damage returns boolean
params
  ship_id:                   long
end

function Execute_Event_Ship_Lose_Movement returns boolean
params
  ship_id:                   long
end

function Execute_Event_Ship_Lose_Supplies returns boolean
params
  ship_id:                   long
end

function Execute_Event_Ship_Cargo_Damage returns boolean
params
  ship_id:                   long
end

function Execute_Event_Ship_Rebels returns boolean
params
  ship_id:                   long
end

function Execute_Event_Ship_Experience_Change returns boolean
params
  ship_id:                   long
end

function Execute_Event_Ship_Orders_Change returns boolean
params
  ship_id:                   long
end

function Execute_Event_Ship_Moved returns boolean
params
  ship_id:                   long
end

function Execute_Event_Minefield_Damage returns boolean
params
  sobj_id:                   long
end

function Execute_Event_Planet_Conditions_Change returns boolean
params
  planet_id:                 long
end

function Execute_Event_Planet_Value_Change returns boolean
params
  planet_id:                 long
end

function Execute_Event_Planet_Population_Change returns boolean
params
  planet_id:                 long
end

function Execute_Event_Planet_Population_Happiness_Change returns boolean
params
  planet_id:                 long
end

function Execute_Event_Planet_Population_Riot returns boolean
params
  planet_id:                 long
  bypass_event:              boolean
end

function Execute_Event_Planet_Population_Rebel returns boolean
params
  planet_id:                 long
  bypass_event:              boolean
end

function Execute_Event_Planet_Cargo_Damage returns boolean
params
  planet_id:                 long
end

function Execute_Event_Planet_Plague_Created returns boolean
params
  planet_id:                 long
end

function Execute_Event_Planet_Plague_Cured returns boolean
params
  planet_id:                 long
end

function Execute_Event_Planet_Created returns boolean
params
  sys_id:                    long
end

function Execute_Event_Planet_Destroyed returns boolean
params
  planet_id:                 long
end

function Execute_Event_Star_Created returns boolean
params
  sys_id:                    long
end

function Execute_Event_Warp_Point_Closed returns boolean
params
  wp_id:                     long
end

function Execute_Event_Warp_Point_Opened returns boolean
params
  sys_id:                    long
end

function Execute_Event_Storm_Created returns boolean
params
  sys_id:                    long
end

function Execute_Event_Storm_Destroyed returns boolean
params
  storm_id:                  long
end

function Execute_Event_Nebulae_Destroyed returns boolean
params
  sys_id:                    long
end

function Execute_Event_Black_Hole_Destroyed returns boolean
params
  sys_id:                    long
end

function Execute_Event_Empire_Points_Change returns boolean
params
  plr_id:                    long
end

function Timed_Events returns boolean
params
end

function Execute_Event_Star_Destroyed_Begin returns boolean
params
  star_id:                   long
end

function Execute_Event_Star_Destroyed_In_Progress returns boolean
params
  star_id:                   long
  time_remaining:            long
end

function Execute_Event_Star_Destroyed_End returns boolean
params
  star_id:                   long
end

function Execute_Event_Nebulae_Created_Begin returns boolean
params
  star_id:                   long
end

function Execute_Event_Nebulae_Created_In_Progress returns boolean
params
  star_id:                   long
  time_remaining:            long
end

function Execute_Event_Nebulae_Created_End returns boolean
params
  star_id:                   long
end

function Execute_Event_Black_Hole_Created_Begin returns boolean
params
  star_id:                    long
end

function Execute_Event_Black_Hole_Created_In_Progress returns boolean
params
  star_id:                   long
  time_remaining:            long
end

function Execute_Event_Black_Hole_Created_End returns boolean
params
  star_id:                   long
end

function Execute_Dimensional_Rift_Damage returns boolean
params
end

function Execute_Subverter_Damage returns boolean
params
end

function Execute_Event_Random_Research returns boolean
params
end

function Execute_Event_Pollution returns boolean
params
end

function Execute_Event_Plague_Spreading returns boolean
params
end

function Execute_Blackhole_Damage returns boolean
params
end

enddeffunc

//------------------------------------------------------------------------
// Main
//------------------------------------------------------------------------
function Main returns boolean
vars
  datafile_id:               long
  datafile_value:            string
  lst_ship_id:               longlist
  list_count:                long
  list_index:                long
  ship_name:                 string
begin

  // Special Event Settings
  set datafile_id := Sys_Load_Datafile(0, "ModEventSettings.txt")

  // Note the frequency and severity of events
  set lng_Event_Frequency := Sys_Game_Settings_Get_External_Events_Frequency()
  set lng_Event_Severity := Sys_Game_Settings_Get_External_Events_Severity()

  // Check ModEventSettings.txt for values
  if (datafile_id > 0) then
    // Research events
    set datafile_value := Sys_Get_Datafile_Field_Value_As_String(datafile_id, "Allow Research Events")
    set bool_ModEventSetting_Allow_Research_Events := (datafile_value = "TRUE")
    // call Sys_Debug_Print("Events", "Value = " + datafile_value)
    // Pollution events
    set datafile_value := Sys_Get_Datafile_Field_Value_As_String(datafile_id, "Allow Pollution Events")
    set bool_ModEventSetting_Allow_Pollution_Events := (datafile_value = "TRUE")
    // call Sys_Debug_Print("Events", "Value = " + datafile_value)
    // Plague Spreading events
    set datafile_value := Sys_Get_Datafile_Field_Value_As_String(datafile_id, "Allow Plague Spreading Events")
    set bool_ModEventSetting_Allow_Plague_Spreading_Events := (datafile_value = "TRUE")
  endif

  // Debug output
  call Sys_Debug_Print("Events", "  - Event Restrictions")
  call Sys_Debug_Print("Events", "    - Allow Research Events = " + Sys_Convert_Boolean_To_String(bool_ModEventSetting_Allow_Research_Events))
  call Sys_Debug_Print("Events", "    - Allow Pollution Events = " + Sys_Convert_Boolean_To_String(bool_ModEventSetting_Allow_Pollution_Events))
  call Sys_Debug_Print("Events", "    - Allow Plague Spreading Events = " + Sys_Convert_Boolean_To_String(bool_ModEventSetting_Allow_Plague_Spreading_Events))

  // Unload settings file
  call Sys_Unload_Datafile(datafile_id)

  // Open events text file
  set lng_Datafile_Event_Text_ID := Sys_Load_Datafile(0, "EventText.txt")

  // Create score reference
  call Verify_Empire_Scores()

  // Run events
  if (lng_Datafile_Event_Text_ID > 0) then
    // Special script for first turn
    if (sys_long_Game_Date = (Sys_Get_Game_Start_Date() + 10)) then
      call Fix_Planet_Names()
    endif
    // Account for remote mining resource depletion in finite resource games
    if Sys_Is_Finite_Resource_Game() then
      call Deplete_Resources_From_Remote_Mining()
    endif
    // Evaluate the map every 5 turns for chokepoint-ness
    if (Sys_Mod_Long(sys_long_Game_Date, 5) = 0) then
      // Debug Output
      call Sys_Debug_Print("Events", "  --------------")
      call Sys_Debug_Print("Events", "  - System Chokepoint-ness Scores")
      call Compute_System_Chokepoint_Scores()
    endif
    // Other events
    call Check_Political_Status()
    call Population_Events()
    call Execute_Dimensional_Rift_Damage()
    call Execute_Subverter_Damage()
    call Execute_Damage_From_Asteroids()
    call Execute_Blackhole_Damage()
    call External_Events()
    call Timed_Events()
    // Optional - Research events
    if (bool_ModEventSetting_Allow_Research_Events) then
      call Execute_Event_Random_Research()
    endif
    // Optional - Pollution events
    if (bool_ModEventSetting_Allow_Pollution_Events) then
      call Execute_Event_Pollution()
    endif
    // Optional - Plague Spreading events
    if (bool_ModEventSetting_Allow_Pollution_Events) then
      call Execute_Event_Plague_Spreading()
    endif

  endif

  call Sys_Unload_Datafile(lng_Datafile_Event_Text_ID)
end

//------------------------------------------------------------------------
// Compute_System_Chokepoint_Scores
//------------------------------------------------------------------------
function Compute_System_Chokepoint_Scores returns boolean
params
vars
  sys_count:                 long
  sys_index:                 long
  sys_index_A:               long
  sys_index_B:               long
  sys_index_C:               long
  dist_sys_AB:               long
  dist_sys_AC:               long
  dist_sys_BC:               long
  choke_score:               long
  max_choke_score:           long := 0
  choke_rating:              long
  lst_sys_choke_score:       longlist
begin

  // For each system, calculate a value of chokepoint-ness
  set sys_count := Sys_Get_Number_Of_Solar_Systems()

  if (sys_count > 0) then
    // Initialize the list variables
    call lst_sys_choke_score.fill(sys_count, 0)

    // Calculate a chokepoint score for each system
    for sys_index_A := 1 to sys_count do
      for sys_index_B := (sys_index_A + 1) to sys_count do
        set dist_sys_AB := Sys_Get_System_Distance_Between_Solar_Systems(sys_index_A, sys_index_B)
        // Don't check if the systems A&B are not connected at all or directly connected
        if (dist_sys_AB >= 2) and (dist_sys_AB <= 4) then
          // Check to see if System C lies on a path between System A and System B
          for sys_index_C := 1 to sys_count do
            // Check the distance to System C from System A and System B
            if (sys_index_C <> sys_index_A) and (sys_index_C <> sys_index_B) then
              set dist_sys_AC := Sys_Get_System_Distance_Between_Solar_Systems(sys_index_A, sys_index_C)
              set dist_sys_BC := Sys_Get_System_Distance_Between_Solar_Systems(sys_index_B, sys_index_C)
              // Check the path length
              if (dist_sys_AC > 0) and (dist_sys_BC > 0) then
                if ((dist_sys_AC + dist_sys_BC) = dist_sys_AB) then
                  // System C is on at least one shortest path between System A & System B
                  set choke_score := lst_sys_choke_score.get(sys_index_C)
                  // Note the chokepoint score for System C
                  call lst_sys_choke_score.set(sys_index_C, choke_score + 1)
                endif
              endif
            endif
          endfor
        endif
      endfor
    endfor

    // Determine the maximum chokepoint score
    for sys_index := 1 to sys_count do
      set choke_score := lst_sys_choke_score.get(sys_index)
      // Is this the new max score?
      if (choke_score > max_choke_score) then
        set max_choke_score := choke_score
      endif
    endfor

    // Calculate a final choke rating for a system on a scale of 0-100 (100 = maximum chokepoint-ness)
    if (max_choke_score > 0) then
      for sys_index := 1 to sys_count do
        set choke_score := lst_sys_choke_score.get(sys_index)
        set choke_rating := Sys_Divide_Long(100 * choke_score, max_choke_score)
        // Store the value in the events memory for computer players to access
        call Sys_Set_Event_Storage_Long(sys_index, choke_rating)
        // Debug output
        call Sys_Debug_Print("Events","  - " + Sys_Get_Solar_System_Name(sys_index) + " System; Chokepoint Rating = " + Sys_Convert_Long_To_String(choke_rating))
      endfor
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Verify_Empire_Scores
//------------------------------------------------------------------------
function Verify_Empire_Scores returns boolean
params
vars
  plr_count:                 long
  plr_index:                 long
  plr_score:                 real
begin

  // Get the number of players
  set plr_count := Sys_Get_Number_Of_Players()

  // Debug output
  call Sys_Debug_Print("Events", "--------------")
  call Sys_Debug_Print("Events", "Empire Scores:")

  // Report their score
  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      set plr_score := Sys_AI_Empire_Stats_Get_Empire_Score(plr_index)
      // Debug output
      call Sys_Debug_Print("Events","  - " + Sys_Empire_Get_Empire_Name(plr_index) + " = " + Sys_Convert_Real_To_String(plr_score))
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Fix_Planet_Names
//------------------------------------------------------------------------
function Fix_Planet_Names returns boolean
params
vars
  planet_list:               longlist
  planet_index:              long
  planet_id:                 long
  planet_name:               string
  new_planet_name:           string
  planet_suffix:             long
begin

  // This function fixes planet names in systems where planets orbit different stars
  // Debug text
  call Sys_Debug_Print("Events", "------------------")
  call Sys_Debug_Print("Events", "Planet Name Fixes:")

  // Create a list of all the planets on the map
  call Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_PLANET, planet_list, FALSE, TRUE, 0)

  if planet_list.count() > 0 then
    for planet_index := 1 to planet_list.count() do
      set planet_id := planet_list.get(planet_index)
      set planet_name := Sys_Get_Space_Object_Name(planet_id)
      set new_planet_name := ""
      // Check the planet name
      if (Sys_Pos_String("Star A", planet_name) > 0) then
        set new_planet_name := Sys_Replace_String(planet_name, "Star A", "I", TRUE, TRUE)
      endif
      if (Sys_Pos_String("Star B", planet_name) > 0) then
        set new_planet_name := Sys_Replace_String(planet_name, "Star B", "II", TRUE, TRUE)
      endif
      if (Sys_Pos_String("Star C", planet_name) > 0) then
        set new_planet_name := Sys_Replace_String(planet_name, "Star C", "III", TRUE, TRUE)
      endif
      // Update the planet Name
      if (new_planet_name <> "") then
        call Sys_Set_Space_Object_Name(planet_id, new_planet_name)
        // Debug output
        call Sys_Debug_Print("Events", "  - Re-named " + planet_name + " to " + new_planet_name)
      endif
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Deplete_Resources_From_Remote_Mining
//------------------------------------------------------------------------
function Deplete_Resources_From_Remote_Mining returns boolean
params
vars
  ship_list:                 longlist
  ship_count:                long
  ship_index:                long
  ship_id:                   long
  ship_owner:                long
  ship_name:                 string
  ship_sys_loc:              long
  ship_sect_loc:             long
  comp_list:                 longlist
  comp_count:                long
  comp_pos_index:            long
  comp_id:                   long
  comp_level:                long
  comp_min_id:               long
  num_comp_min:              long
  comp_min_level:            long
  comp_org_id:               long
  num_comp_org:              long
  comp_org_level:            long
  comp_rad_id:               long
  num_comp_rad:              long
  comp_rad_level:            long
  sobj_list:                 longlist
  sobj_mined_list:           longlist
  sobj_count:                long
  sobj_id:                   long
  sobj_name:                 string
  sobj_owner:                long
  sobj_value:                resources
  sobj_minerals:             long
  sobj_organics:             long
  sobj_radioactives:         long
  rate_minerals:             long
  rate_organics:             long
  rate_radioactives:         long
  new_value:                 resources
  new_minerals:              long
  new_organics:              long
  new_radioactives:          long
begin

  // Check each unowned planet and asteroid field for remote mining activities
  call Sys_Debug_Print("Events", "-----------------------------------")
  call Sys_Debug_Print("Events", "Remote Mining Resource Adjustments:")

  // Get a list of all the ships
  set ship_count := Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_SHIP, ship_list, TRUE, FALSE, 0)

  if (ship_count > 0) then
    for ship_index := 1 to ship_count do
      set ship_id := ship_list.get(ship_index)
      set ship_name := Sys_Get_Space_Object_Name(ship_id)
      set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
      set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
      set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
      // Reset Variables
      set num_comp_min := 0
      set num_comp_org := 0
      set num_comp_rad := 0
      set rate_minerals := 0
      set rate_organics := 0
      set rate_radioactives := 0
      // Get the component IDs for the remote mining components
      set comp_min_id := Sys_Get_Component_With_Name(ship_owner, "Robo-Miners")
      set comp_org_id := Sys_Get_Component_With_Name(ship_owner, "Robo-Farmers")
      set comp_rad_id := Sys_Get_Component_With_Name(ship_owner, "Robo-Extractors")
      // Only proceed with the check if the ship owner has the components available for remote mining
      if (comp_min_id > 0) or (comp_org_id > 0) or (comp_rad_id > 0) then
        // Is there an unowned planet in the same sector?
        set sobj_count := Sys_Get_List_Of_Visible_Space_Objects_In_Sector(ship_owner, SPACE_OBJECT_TYPE_PLANET, ship_sys_loc, ship_sect_loc, sobj_list)
        // If no planet, check for asteroids in the same sector
        if (sobj_count = 0) then
          set sobj_count := Sys_Get_List_Of_Visible_Space_Objects_In_Sector(ship_owner, SPACE_OBJECT_TYPE_ASTEROIDS, ship_sys_loc, ship_sect_loc, sobj_list)
        endif
        // If there is a planet or asteroid field is present...
        if (sobj_count > 0) then
          set sobj_id := sobj_list.get(1)
          // Check for an owner
          set sobj_owner := Sys_Get_Space_Object_Owner(sobj_id)
          // Is this a mined object already?
          if (sobj_mined_list.indexof(sobj_id) > 0) then
            set sobj_owner := -1
          endif
          // If no owner
          if (sobj_owner = 0) then
            // Note the planet/asteroid resource value
            set sobj_name := Sys_Get_Space_Object_Name(sobj_id)
            set sobj_value := Sys_Get_Space_Object_Planet_Value(sobj_id)
            set sobj_minerals := Sys_Trunc(sobj_value.get(RESOURCE_TYPE_MINERALS))
            set sobj_organics := Sys_Trunc(sobj_value.get(RESOURCE_TYPE_ORGANICS))
            set sobj_radioactives := Sys_Trunc(sobj_value.get(RESOURCE_TYPE_RADIOACTIVES))
            // Check the components of the ship present
            set comp_count := Sys_Get_Space_Object_Comp_Count(ship_id)
            // Check for remote mining components, if present count how many there are
            if (comp_count > 0) then
              for comp_pos_index := 1 to comp_count do
                set comp_id := Sys_Get_Space_Object_Comp_Info_Comp_ID(ship_id, comp_pos_index)
                set comp_level := Sys_Get_Space_Object_Comp_Info_Comp_Level(ship_id, comp_pos_index)
                // Robo-Miners
                if (comp_id = comp_min_id) then
                  set num_comp_min := num_comp_min + 1
                  set comp_min_level := comp_level
                endif
                // Robo-Farmers
                if (comp_id = comp_org_id) then
                  set num_comp_org := num_comp_org + 1
                  set comp_org_level := comp_level
                endif
                // Robo-Extractors
                if (comp_id = comp_rad_id) then
                  set num_comp_rad := num_comp_rad + 1
                  set comp_rad_level := comp_level
                endif
              endfor
              // Calculate the depletion rate
              if (num_comp_min > 0) then
                set rate_minerals := num_comp_min * ((comp_min_level * 25) + 225)
              endif
              if (num_comp_org > 0) then
                set rate_organics := num_comp_org * ((comp_org_level * 25) + 225)
              endif
              if (num_comp_rad > 0) then
                set rate_radioactives := num_comp_rad * ((comp_rad_level * 25) + 225)
              endif
              // Don't have the object's value go less than zero!
              if (rate_minerals >= sobj_minerals) then
                set rate_minerals := sobj_minerals
              endif
              if (rate_organics >= sobj_organics) then
                set rate_organics := sobj_organics
              endif
              if (rate_radioactives >= sobj_radioactives) then
                set rate_radioactives := sobj_radioactives
              endif
              // Deduct the remotely mined resources for this turn
              if (rate_minerals > 0) or (rate_organics > 0) or (rate_radioactives > 0) then
                call Sys_Change_Planet_Value(sobj_id, -rate_minerals, RESOURCE_TYPE_MINERALS)
                call Sys_Change_Planet_Value(sobj_id, -rate_organics, RESOURCE_TYPE_ORGANICS)
                call Sys_Change_Planet_Value(sobj_id, -rate_radioactives, RESOURCE_TYPE_RADIOACTIVES)
                // Note new value
                set new_value := Sys_Get_Space_Object_Planet_Value(sobj_id)
                set new_minerals := Sys_Trunc(new_value.get(RESOURCE_TYPE_MINERALS))
                set new_organics := Sys_Trunc(new_value.get(RESOURCE_TYPE_ORGANICS))
                set new_radioactives := Sys_Trunc(new_value.get(RESOURCE_TYPE_RADIOACTIVES))
                // Add to our list of mined objects
                call sobj_mined_list.add(sobj_id)
                // Debug Output
                call Sys_Debug_Print("Events", "  - " + sobj_name)
                call Sys_Debug_Print("Events", "    - Mining by " + ship_name + "; Rate = " + Sys_Convert_Long_To_String(rate_minerals) + " kT min; " + Sys_Convert_Long_To_String(rate_organics) + " kT org; " + Sys_Convert_Long_To_String(rate_radioactives) + " kT rad")
                call Sys_Debug_Print("Events", "    - Prev value = " + Sys_Convert_Long_To_String(sobj_minerals) + " kT min; " + Sys_Convert_Long_To_String(sobj_organics) " kT org; " + Sys_Convert_Long_To_String(sobj_radioactives) " kT rad")
                call Sys_Debug_Print("Events", "    - New value = " + Sys_Convert_Long_To_String(new_minerals) + " kT min; " + Sys_Convert_Long_To_String(new_organics) " kT org; " + Sys_Convert_Long_To_String(new_radioactives) " kT rad")
              endif
            endif
          endif
        endif
      endif
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Damage_From_Asteroids
//------------------------------------------------------------------------
function Execute_Damage_From_Asteroids returns boolean
params
vars
  ship_list:                 longlist
  ship_count:                long
  ship_index:                long
  ship_id:                   long
  ship_owner:                long
  ship_name:                 string
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_structure:            long
  ship_armor:                long
  ship_shields:              long
  ship_hitpoints:            long
  ship_destroyed:            boolean
  sobj_list:                 longlist
  sobj_count:                long
  sobj_id:                   long
  sobj_name:                 string
  dmg_chance:                long
  dmg_amount:                long
  log_type:                  long
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
begin

  // Check for ships in asteroid fields to possibly apply damage
  call Sys_Debug_Print("Events", "")
  call Sys_Debug_Print("Events", "----------------------")
  call Sys_Debug_Print("Events", "Damage From Asteroids:")

  // Get a list of all the ships
  set ship_count := Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_SHIP, ship_list, TRUE, FALSE, 0)

  if (ship_count > 0) then
    for ship_index := 1 to ship_count do
      set ship_id := ship_list.get(ship_index)
      set ship_name := Sys_Get_Space_Object_Name(ship_id)
      set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
      set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
      set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
      // Is there are an asteroid field in this sector?
      set sobj_count := Sys_Get_List_Of_Visible_Space_Objects_In_Sector(ship_owner, SPACE_OBJECT_TYPE_ASTEROIDS, ship_sys_loc, ship_sect_loc, sobj_list)
      // If there an asteroid field is present...
      if (sobj_count > 0) then
        set sobj_id := sobj_list.get(1)
        set sobj_name := Sys_Get_Space_Object_Name(sobj_id)
        // Get the ship's stats
        set ship_structure := Sys_Get_Space_Object_Total_Tonnage_Structure(ship_id)
        set ship_armor := Sys_Get_Space_Object_Current_Armor_Structure(ship_id)
        set ship_shields := Sys_Get_Space_Object_Current_Shields(ship_id)
        set ship_hitpoints := ship_structure + ship_armor + ship_shields
        set ship_destroyed := FALSE
        set dmg_amount := 0
        // Are we lucky?
        if Sys_Does_Empire_Have_Ability(ship_owner, "Bad Event Chance") then
          set dmg_chance := 500
        else
          set dmg_chance := 250
        endif
        // Chance for Damage
        if (Sys_Get_Random_Long(1, dmg_chance) <= 5) then
          // Do Damage
          if Sys_Get_Random_Long(1, 5) = 1 then
            // Catastrophic Damage
            set dmg_amount := Sys_Get_Random_Long(10, 50) * 100
          else
            // Non-Catastrophic Damage
            set dmg_amount := Sys_Get_Random_Long(10, 50) * 10
          endif
        endif
        // Apply Damage
        if (dmg_amount > 0) then
          call Sys_Space_Object_Take_Damage(ship_id, "Normal", dmg_amount)
          // Was the ship destroyed?
          if (dmg_amount > ship_hitpoints) then
            set ship_destroyed := TRUE
          endif

          // Log Message to owner
          set log_type := LOG_TYPE_SHIP_DAMAGED

          // Event cause
          case Sys_Get_Random_Long(1, 4)
            1:
              set event_cause := "An asteroid strike"
            2:
              set event_cause := "Asteroid debris"
            3:
              set event_cause := "An asteroid collision"
            4:
              set event_cause := "A micrometeoroid shower"
          endcase

          // Compose the message
          if (ship_destroyed) then
            set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 2 Title")
            set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 2 Text")
            set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 2 Small Picture Filename")
            set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 2 Large Picture Filename")
          else
            set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 1 Title")
            set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 1 Text")
            set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 1 Small Picture Filename")
            set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 1 Large Picture Filename")
          endif

          set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
          set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", ship_name, TRUE, TRUE)
          set message_text := Sys_Replace_String(message_text, "[%DamageAmount%]", Sys_Convert_Long_To_String(dmg_amount), TRUE, TRUE)
          set message_text := Sys_Replace_String(message_text, "[%DamageType%]", "kT of damage", TRUE, TRUE)
          set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(ship_sys_loc), TRUE, TRUE)
          set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(ship_sect_loc), TRUE, TRUE)

          call Give_Message_To_Players(MESSAGE_TO_OWNER, ship_owner, ship_sys_loc, ship_sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
          // Debug Output
          call Sys_Debug_Print("Events", "  - " + ship_name)
        endif
      endif
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Check_Political_Status
//------------------------------------------------------------------------
function Check_Political_Status returns boolean
params
vars
  num_players:               long
  plr_index:                 long
  trg_plr_index:             long
  pol_status:                long
  treaty_name:               string
  empire_name:               string
  trg_empire_name:           string
  message_title:             string
  message_text:              string
begin

  // Debug text
  call Sys_Debug_Print("Events", "")
  call Sys_Debug_Print("Events", "-------------")
  call Sys_Debug_Print("Events", "Treaty Check:")

  // Get the number of players
  set num_players := Sys_Get_Number_Of_Players()

  // Check the player's status with other players, if they have a treaty make sure the name is not illegal (ie naming it "War")
  if (num_players > 0) then
    for plr_index := 1 to num_players do
      set empire_name := Sys_Empire_Get_Empire_Name(plr_index)
      // Check the political status with each of the other players
      if (num_players > 0) then
        for trg_plr_index := 1 to num_players do
          if (plr_index <> trg_plr_index) then
            set trg_empire_name := Sys_Empire_Get_Empire_Name(trg_plr_index)
            set pol_status := Sys_Empire_Politics_Get_Political_Status_Between_Players(plr_index, trg_plr_index)
            // Get the actual political status
            case pol_status
              POLITICAL_STATUS_TYPE_UNKNOWN:
                set treaty_name := "No Contact"
              POLITICAL_STATUS_TYPE_KNOWN:
                set treaty_name := "None"
              POLITICAL_STATUS_TYPE_WAR:
                set treaty_name := "Real War"
              POLITICAL_STATUS_TYPE_TREATY:
                set treaty_name := Sys_Empire_Politics_Get_Treaty_Name_Between_Players(plr_index, trg_plr_index)
                // Check to see if the player has named the treaty one of the political status types to trick other players
                If (treaty_name = "War") or (treaty_name = "WAR") or (treaty_name = "None") or (treaty_name = "NONE") then
                  set message_title := "Fake Political Status Alert!"
                  set message_text := "The " + empire_name + " has a real treaty with the " + trg_empire_name + " and is trying to disguise it with the name War/None to trick other players."
                  // Debug output
                  call Sys_Debug_Print("Events", "  - Treaty disguised as War/None between " + empire_name " and " + trg_empire_name + "!")
                  // Send a message to all players
                  call Give_Message_To_Players(MESSAGE_TO_ALL, 0, 0, 0, message_title, message_text, "Event_ProblemDetected.jpg", "LargePortrait_Event_ProblemDetected.jpg", LOG_TYPE_MESSAGE)
                endif
            endcase
          endif
        endfor
      endif
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Population_Events
//------------------------------------------------------------------------
function Population_Events returns boolean
params
vars
  num_players:               long
  plr_index:                 long
  trg_index:                 long
  lst_colonies:              longlist
  planet_count:              long
  planet_index:              long
  planet_id:                 long
  planet_name:               string
  planet_conditions:         real
  base_happiness:            long
  pop_happiness_mod:         long
  pop_happiness:             long
  pop_type_count:            long
  pop_loyalty:               long
  total_pop_loyalty:         long
  pop_happiness_change:      long
  war_tolerance_mod:         long
  war_happiness_factor:      long
  war_pct_happiness_change:  long
  war_happiness_change:      long
  total_war_time:            long
  pol_status:                long
  cargo_item_count:          long
  cargo_item_index:          long
  cargo_item_id:             long
  cargo_item_type:           long
  log_type:                  long
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Debug text
  call Sys_Debug_Print("Events", "")
  call Sys_Debug_Print("Events", "------------------")
  call Sys_Debug_Print("Events", "Population Events:")

  // Get the number of players
  set num_players := Sys_Get_Number_Of_Players()

  // For each player, cycle through their colonies and determine if any population events should occur
  if (num_players > 0) then
    // Determine the happiness modifiers to apply to each player's colonies 
    for plr_index := 1 to num_players do
      set total_war_time := 0
      set war_happiness_change := 0

      // Debug output
      call Sys_Debug_Print("Events", "  - " + Sys_Empire_Get_Empire_Name(plr_index))

      // Set the player's base happiness and war tolerance levels based on their Government type
      case Sys_Get_Empire_Government_Type(plr_index)
        "Anarchy":
          set base_happiness := 75
          set war_tolerance_mod := -25
        "Democracy":
          set base_happiness := 70
          set war_tolerance_mod := -25
        "Corporate":
          set base_happiness := 60
          set war_tolerance_mod := -10
        "Republic":
          set base_happiness := 65
          set war_tolerance_mod := -25
        "Oligarchy":
          set base_happiness := 60
          set war_tolerance_mod := 0
        "Theocracy":
          set base_happiness := 55
          set war_tolerance_mod := 25
        "Monarchy":
          set base_happiness := 55
          set war_tolerance_mod := 10
        "Tyranny":
          set base_happiness := 50
          set war_tolerance_mod := 25
        "Hive":
          set base_happiness := 55
          set war_tolerance_mod := 50
        "Collective":
          set base_happiness := 50
          set war_tolerance_mod := 50
      endcase

      // Determine the active number of turns at war for each player
      for trg_index := 1 to num_players do
        set pol_status := Sys_Empire_Politics_Get_Status_With_Player(plr_index, trg_index)
        // Add up the player's time at war with all other players
        if (pol_status = POLITICAL_STATUS_TYPE_WAR) then
          set total_war_time := total_war_time + Sys_Empire_Politics_Get_Status_Time_With_Player(plr_index, trg_index)
        endif
      endfor
      // Debug output
      call Sys_Debug_Print("Events", "    - Current accumulated turns at war = " + Sys_Convert_Long_To_String(total_war_time))

      if (total_war_time > 0) then
        set war_happiness_factor := Sys_Trunc(total_war_time ^ 0.5) * 5 * (100 - war_tolerance_mod)
        set war_pct_happiness_change := Sys_Divide_Long(war_happiness_factor, 1000)
        set war_pct_happiness_change := Sys_Min_Long(10, war_pct_happiness_change)
        call Sys_Debug_Print("Events", "    - War Happiness Factor = " + Sys_Convert_Long_To_String(war_pct_happiness_change) + "%")
        // Make a log message if the happiness crosses a threshold
        if (war_happiness_change >= 5) then
          // Log Message to owner
          set log_type := LOG_TYPE_POPULATION_ANGRY
          set message_title := "Population Happiness Warning"
          set message_text  := "Sire, our population is becoming increasingly discontent due to our ongoing conflicts."
          set msg_small_pic := "Event_PopulationAngry.jpg"
          set msg_large_pic := "LargePortrait_Event_PopulationAngry.jpg"
          call Give_Message_To_Players(MESSAGE_TO_OWNER, plr_index, 0, 0, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
        endif
      endif

      // Get the number of the colonies the player has
      set planet_count := Sys_Get_List_Of_Players_Colonies(plr_index, lst_colonies)
      // Cycle through each colony to check for happiness and loyalty levels
      if (planet_count > 0) then
        for planet_index := 1 to planet_count do
          set planet_id := lst_colonies.get(planet_index)
          set planet_name := Sys_Get_Space_Object_Name(planet_id)
          set planet_conditions := Sys_Get_Planet_Conditions(planet_id)

          // Is the planet's population affected by happiness?
          if Sys_Is_Planet_Effected_By_Happiness(planet_id) then
            // Get the planet's details
            set pop_happiness := Sys_Get_Planet_Happiness(planet_id)
            set pop_type_count := 0
            set pop_loyalty := 0

            // Debug text
            call Sys_Debug_Print("Events", "    - " + planet_name + " (" + Sys_Convert_Long_To_String(pop_happiness) + "%)")

            // Adjust the planet's population happiness for the Empire's government type
            // Adjust population happiness modifier strength for increasing or decreasing happiness trend
            if (base_happiness > pop_happiness) then
              set pop_happiness_mod := 10
            else
              set pop_happiness_mod := 5
            endif

            // Adjust population happiness modifier for computer difficulty
            if Sys_Are_We_Computer_Player(plr_index) then
              if (base_happiness > pop_happiness) then
                case Sys_Game_Settings_Get_AI_Difficulty()
                  1:
                    set pop_happiness_mod := 3
                  2:
                    set pop_happiness_mod := 4
                  3:
                    set pop_happiness_mod := 5
                endcase
              else
                case Sys_Game_Settings_Get_AI_Difficulty()
                  1:
                    set pop_happiness_mod := 5
                  2:
                    set pop_happiness_mod := 4
                  3:
                    set pop_happiness_mod := 3
                endcase
              endif
            endif

            // Adjust the planet's population happiness for government type
            set pop_happiness_change := Sys_Divide_Long(pop_happiness - base_happiness, pop_happiness_mod)
            // Don't allow the happiness change to be more than the happiness level
            set pop_happiness_change := Sys_Min_Long(pop_happiness_change, pop_happiness)

            if (pop_happiness_change <> 0) then
              call Sys_Change_Planet_Population_Happiness(planet_id, pop_happiness_change)
              // Debug output
              call Sys_Debug_Print("Events", "      - Government = " + Sys_Convert_Long_To_String(-pop_happiness_change) + "%")
            endif

            // Adjust our planet's happiness for war tolerance
            if (war_pct_happiness_change > 0) then
              // Adjust for the planet's current happiness level
              set war_happiness_change := Sys_Trunc(pop_happiness * war_pct_happiness_change / 100)
              // Apply the change
              call Sys_Change_Planet_Population_Happiness(planet_id, war_happiness_change)
              // Debug output
              call Sys_Debug_Print("Events", "      - War = " + Sys_Convert_Long_To_String(-war_happiness_change) + "%")
            endif

            // Check our planet's population groups to get their loyalty
            set cargo_item_count := Sys_Get_Space_Object_Cargo_Item_Count(planet_id)

            if (cargo_item_count > 0) then
              for cargo_item_index := 1 to cargo_item_count do
                set cargo_item_id := Sys_Get_Space_Object_Cargo_Item_ID(planet_id, cargo_item_index)
                set cargo_item_type := Sys_Get_Space_Object_Cargo_Item_Type(planet_id, cargo_item_id)
                // Get the population's loyalty
                if (cargo_item_type = CARGO_ITEM_TYPE_POPULATION) then
                  set pop_type_count := pop_type_count + 1
                  set pop_loyalty := Sys_Get_Space_Object_Cargo_Item_Population_Loyalty(planet_id, cargo_item_id)
                  set total_pop_loyalty := total_pop_loyalty + pop_loyalty
                  // Debug output
                  call Sys_Debug_Print("Events", "      - Loyalty = " + Sys_Convert_Long_To_String(pop_loyalty) + "%")
                endif
              endfor
              // Get the population's average loyalty if 2 or more races are present
              if (pop_type_count > 1) then
                set pop_loyalty := Sys_Divide_Long(total_pop_loyalty, pop_type_count)
              endif
            endif
            // If the population is becoming disloyal, reduce the planet's happiness
            if (pop_loyalty < 90) then
              set pop_happiness_change := Sys_Divide_Long(100 - pop_loyalty, 10)
              // Change the population's happiness
              if (pop_happiness_change > 0) then
                call Sys_Change_Planet_Population_Happiness(planet_id, pop_happiness_change)
                set pop_happiness := Sys_Max_Long(0, pop_happiness - pop_happiness_change)
                // Debug output
                call Sys_Debug_Print("Events", "      - Disloyalty = " + Sys_Convert_Long_To_String(-pop_happiness_change) + "%")
              endif
            endif

            // Deadly
            if (planet_conditions < 0.30) then
              set pop_happiness_change := 5
            endif
            // Harsh
            if (planet_conditions >= 0.30) and (planet_conditions < 0.50) then
              set pop_happiness_change := 3
            endif
            // Unpleasant
            if (planet_conditions >= 0.50) and (planet_conditions < 1.00) then
              set pop_happiness_change := 1
            endif
            // Mild
            if (planet_conditions >= 1.00) and (planet_conditions < 1.30) then
              set pop_happiness_change := -1
            endif
            // Good
            if (planet_conditions >= 1.30) and (planet_conditions < 1.50) then
              set pop_happiness_change := -3
            endif
            // Optimal
            if (planet_conditions >= 1.50) then
              set pop_happiness_change := -5
            endif

            // Adjust the happiness for computer player difficulty
            if (pop_happiness_change <> 0) then
              if Sys_Are_We_Computer_Player(plr_index) then
                case Sys_Game_Settings_Get_AI_Difficulty()
                  1:
                    set pop_happiness_change := pop_happiness_change
                  2:
                    set pop_happiness_change := pop_happiness_change - 1
                  3:
                    set pop_happiness_change := pop_happiness_change - 2
                endcase
              endif
              // Don't allow the happiness change to be more than the happiness level
              set pop_happiness_change := Sys_Min_Long(pop_happiness_change, pop_happiness)
              // Adjust planet population happiness for its current conditions
              call Sys_Change_Planet_Population_Happiness(planet_id, pop_happiness_change)
              // Debug output
              call Sys_Debug_Print("Events", "      - Conditions = " + Sys_Convert_Long_To_String(-pop_happiness_change) + "%")
            endif

            // Report the new happiness level
            set pop_happiness := Sys_Get_Planet_Happiness(planet_id)
            // Debug output
            call Sys_Debug_Print("Events", "      - New Happiness Amount = " + Sys_Convert_Long_To_String(pop_happiness) + "%")
 
            // If the happiness and loyalty levels are very low, set a chance for the planet to rebel
            if (pop_happiness < 5) and (pop_loyalty < 10) then
              if (Sys_Get_Random_Long(1, 10 + pop_happiness + pop_loyalty) = 1) then
                call Execute_Event_Planet_Population_Rebel(planet_id, TRUE)
              endif
            endif
            // If the population is rioting, set a chance for the planet to rebel
            if (pop_happiness < 1) then
              case Sys_Game_Settings_Get_External_Events_Frequency()
                EVENT_FREQUENCY_NONE:
                  // Never happens
                EVENT_FREQUENCY_LOW:
                  // Small chance
                  if (Sys_Get_Random_Long(1, 50) = 1) then
                    call Execute_Event_Planet_Population_Rebel(planet_id, TRUE)
                  endif
                EVENT_FREQUENCY_MEDIUM:
                  // Medium chance
                  if (Sys_Get_Random_Long(1, 25) = 1) then
                    call Execute_Event_Planet_Population_Rebel(planet_id, TRUE)
                  endif
                EVENT_FREQUENCY_HIGH:
                  // High chance
                  if (Sys_Get_Random_Long(1, 16) = 1) then
                    call Execute_Event_Planet_Population_Rebel(planet_id, TRUE)
                  endif
              endcase
            endif
          endif
        endfor
      endif
    endfor
  endif
end

//------------------------------------------------------------------------
// External_Events
//------------------------------------------------------------------------
function External_Events returns boolean
vars
  num_players:               long
  event_happened:            boolean := FALSE
  chance:                    long
  low_freq:                  long := 25
  med_freq:                  long := 50
  high_freq:                 long := 75
  event_id:                  long
begin

  // Get the number of players
  set num_players := Sys_Get_Number_Of_Players()

  // Get the frequency and severity of events
  set chance := Sys_Get_Random_Long(1, 100)

  // Debug output
  call Sys_Debug_Print("Events", "")
  call Sys_Debug_Print("Events", "Events")
  call Sys_Debug_Print("Events", "------")

  // Modify the frequency rates based on the number of players
  if (num_players > 10) then
    set low_freq := low_freq + 25
    set med_freq := med_freq + 25
    set high_freq := high_freq + 25
  endif

  // Set the event frequency
  case lng_Event_Frequency
    EVENT_FREQUENCY_NONE:
      set event_happened := FALSE
    EVENT_FREQUENCY_LOW:
      if (chance <= low_freq) then
        set event_happened := TRUE
      endif
    EVENT_FREQUENCY_MEDIUM:
      if (chance <= med_freq) then
        set event_happened := TRUE
      endif
    EVENT_FREQUENCY_HIGH:
      if (chance <= high_freq) then
        set event_happened := TRUE
      endif
  endcase

  // No events in the first 20 turns!
  if (sys_long_game_date <= (Sys_Get_Game_Start_Date() + 20)) then
    set event_happened := FALSE
  endif

  if (lng_Event_Severity > 0) then
    set lng_Event_Severity := Sys_Get_Random_Long(0, lng_Event_Severity)
  endif

  // If an event should occur, then select the event and execute it
  if (event_happened) then
    // Pick the specific event to execute
    set event_id := Select_Event(lng_Event_Severity)
    // Execute it
    if (event_id > 0) then
      call Execute_Event(event_id)
    endif
  endif

end

//------------------------------------------------------------------------
// Select_Event
//------------------------------------------------------------------------
function Select_Event returns long
params
  event_severity:            long
vars
  event_id:                  long := 0
  index:                     long
  pick_list:                 longlist
  weight_list:               longlist
  total_weight:              long
  this_weight:               long
  pick_amount:               long
  list_count:                long
begin

  // Low Severity Events (775 weight)
  if (event_severity >= EVENT_SEVERITY_LOW) then
    call pick_list.add(EVENT_ID_SHIP_DAMAGE)
    call weight_list.add(100)
    call pick_list.add(EVENT_ID_SHIP_LOSE_MOVEMENT)
    call weight_list.add(50)
    call pick_list.add(EVENT_ID_SHIP_LOSE_SUPPLIES)
    call weight_list.add(50)
    call pick_list.add(EVENT_ID_SHIP_CARGO_DAMAGE)
    call weight_list.add(50)
    call pick_list.add(EVENT_ID_SHIP_REBELS)
    call weight_list.add(25)
    call pick_list.add(EVENT_ID_SHIP_EXPERIENCE_CHANGE)
    call weight_list.add(50)
    call pick_list.add(EVENT_ID_SHIP_ORDERS_CHANGE)
    call weight_list.add(50)
    call pick_list.add(EVENT_ID_SHIP_MOVED)
    call weight_list.add(50)
    call pick_list.add(EVENT_ID_MINEFIELD_DAMAGE)
    call weight_list.add(150)
    call pick_list.add(EVENT_ID_PLANET_CONDITIONS_CHANGE)
    call weight_list.add(50)
    call pick_list.add(EVENT_ID_PLANET_VALUE_CHANGE)
    call weight_list.add(50)
    call pick_list.add(EVENT_ID_PLANET_POPULATION_CHANGE)
    call weight_list.add(50)
    call pick_list.add(EVENT_ID_PLANET_POPULATION_HAPPINESS_CHANGE)
    call weight_list.add(50)
  endif

  // Medium Severity Events (125 weight)
  if (event_severity >= EVENT_SEVERITY_MEDIUM) then
    call pick_list.add(EVENT_ID_PLANET_POPULATION_RIOT)
    call weight_list.add(25)
    call pick_list.add(EVENT_ID_PLANET_CARGO_DAMAGE)
    call weight_list.add(25)
    call pick_list.add(EVENT_ID_PLANET_PLAGUE_CREATED)
    call weight_list.add(25)
    call pick_list.add(EVENT_ID_PLANET_PLAGUE_CURED)
    call weight_list.add(25)
    call pick_list.add(EVENT_ID_EMPIRE_POINTS_CHANGE)
    call weight_list.add(25)
  endif

  // High Severity Events (85 weight)
  if (event_severity >= EVENT_SEVERITY_HIGH) then
    call pick_list.add(EVENT_ID_PLANET_POPULATION_REBEL)
    call weight_list.add(10)
    call pick_list.add(EVENT_ID_PLANET_CREATED)
    call weight_list.add(10)
    call pick_list.add(EVENT_ID_PLANET_DESTROYED)
    call weight_list.add(10)
    call pick_list.add(EVENT_ID_WARP_POINT_CLOSED)
    call weight_list.add(10)
    call pick_list.add(EVENT_ID_WARP_POINT_OPENED)
    call weight_list.add(10)
    call pick_list.add(EVENT_ID_STAR_CREATED)
    call weight_list.add(5)
    call pick_list.add(EVENT_ID_STORM_CREATED)
    call weight_list.add(10)
    call pick_list.add(EVENT_ID_STORM_DESTROYED)
    call weight_list.add(10)
    call pick_list.add(EVENT_ID_NEBULAE_DESTROYED)
    call weight_list.add(5)
    call pick_list.add(EVENT_ID_BLACK_HOLE_DESTROYED)
    call weight_list.add(5)
  endif

  // Catastrophic Severity Events (15 weight)
  if (event_severity >= EVENT_SEVERITY_CATASTROPHIC) then
    call pick_list.add(EVENT_ID_STAR_DESTROYED)
    call weight_list.add(5)
    call pick_list.add(EVENT_ID_NEBULAE_CREATED)
    call weight_list.add(5)
    call pick_list.add(EVENT_ID_BLACK_HOLE_CREATED)
    call weight_list.add(5)
  endif

  // Weigh the events
  set list_count := pick_list.count()
  if (list_count > 0) then
    set total_weight := 0
    for index := 1 to list_count do
      set total_weight := total_weight + weight_list.get(index)
    endfor
    set pick_amount := Sys_Get_Random_Long(1, total_weight)

    // Choose the event to occur from the weighted list
    set total_weight := 0
    for index := 1 to list_count do
      set this_weight := weight_list.get(index)
      if (pick_amount >= total_weight) and (pick_amount <= (total_weight + this_weight)) then
        set event_id := pick_list.get(index)
      endif
      set total_weight := total_weight + this_weight
    endfor
  endif

  return event_id
end

//------------------------------------------------------------------------
// Execute_Event
//------------------------------------------------------------------------
function Execute_Event returns boolean
params
  event_id:                  long
vars
  retval:                    boolean := FALSE
  obj_id:                    long := 0
begin

  // Execute the event
  case event_id
    EVENT_ID_SHIP_DAMAGE:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SHIP)
      if (obj_id > 0) then
        set retval := Execute_Event_Ship_Damage(obj_id)
      endif
    EVENT_ID_SHIP_LOSE_MOVEMENT:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SHIP)
      if (obj_id > 0) then
        set retval := Execute_Event_Ship_Lose_Movement(obj_id)
      endif
    EVENT_ID_SHIP_LOSE_SUPPLIES:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SHIP)
      if (obj_id > 0) then
        set retval := Execute_Event_Ship_Lose_Supplies(obj_id)
      endif
    EVENT_ID_SHIP_CARGO_DAMAGE: 
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SHIP)
      if (obj_id > 0) then
        set retval := Execute_Event_Ship_Cargo_Damage(obj_id)
      endif
    EVENT_ID_SHIP_REBELS:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SHIP)
      if (obj_id > 0) and (Sys_Empire_Politics_Get_Number_Of_Known_Players(sys_long_Player_ID) > 1) then
        set retval := Execute_Event_Ship_Rebels(obj_id)
      endif
    EVENT_ID_SHIP_EXPERIENCE_CHANGE:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SHIP)
      if (obj_id > 0) then
        set retval := Execute_Event_Ship_Experience_Change(obj_id)
      endif
    EVENT_ID_SHIP_ORDERS_CHANGE:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SHIP)
      if (obj_id > 0) and (Sys_Get_Space_Object_Maximum_Movement(obj_id) > 0) then
        set retval := Execute_Event_Ship_Orders_Change(obj_id)
      endif
    EVENT_ID_SHIP_MOVED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SHIP)
      if (obj_id > 0) then
        set retval := Execute_Event_Ship_Moved(obj_id)
      endif
    EVENT_ID_MINEFIELD_DAMAGE:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_UNITGROUP)
      if (obj_id > 0) then
        set retval := Execute_Event_Minefield_Damage(obj_id)
      endif
    EVENT_ID_PLANET_CONDITIONS_CHANGE:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLANET)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Conditions_Change(obj_id)
      endif
    EVENT_ID_PLANET_VALUE_CHANGE:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLANET)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Value_Change(obj_id)
      endif
    EVENT_ID_PLANET_POPULATION_CHANGE:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLANET)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Population_Change(obj_id)
      endif
    EVENT_ID_PLANET_POPULATION_HAPPINESS_CHANGE:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLANET)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Population_Happiness_Change(obj_id)
      endif
    EVENT_ID_PLANET_POPULATION_RIOT:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLANET)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Population_Riot(obj_id, FALSE)
      endif
    EVENT_ID_PLANET_POPULATION_REBEL:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLANET)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Population_Rebel(obj_id, FALSE)
      endif
    EVENT_ID_PLANET_CARGO_DAMAGE:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLANET)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Cargo_Damage(obj_id)
      endif
    EVENT_ID_PLANET_PLAGUE_CREATED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLANET)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Plague_Created(obj_id)
      endif
    EVENT_ID_PLANET_PLAGUE_CURED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLANET)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Plague_Cured(obj_id)
      endif
    EVENT_ID_PLANET_CREATED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SYSTEM)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Created(obj_id)
      endif
    EVENT_ID_PLANET_DESTROYED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLANET)
      if (obj_id > 0) then
        set retval := Execute_Event_Planet_Destroyed(obj_id)
      endif
    EVENT_ID_STAR_CREATED: 
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SYSTEM)
      if (obj_id > 0) then
        set retval := Execute_Event_Star_Created(obj_id)
      endif
    EVENT_ID_STAR_DESTROYED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_STAR)
      if (obj_id > 0) then
        set retval := Execute_Event_Star_Destroyed_Begin(obj_id)
      endif
    EVENT_ID_WARP_POINT_CLOSED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_WARP_POINT)
      if (obj_id > 0) then
        set retval := Execute_Event_Warp_Point_Closed(obj_id)
      endif
    EVENT_ID_WARP_POINT_OPENED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SYSTEM)
      if (obj_id > 0) then
        set retval := Execute_Event_Warp_Point_Opened(obj_id)
      endif
    EVENT_ID_STORM_CREATED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_SYSTEM)
      if (obj_id > 0) then
        set retval := Execute_Event_Storm_Created(obj_id)
      endif
    EVENT_ID_STORM_DESTROYED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_STORM)
      if (obj_id > 0) then
        set retval := Execute_Event_Storm_Destroyed(obj_id)
      endif
    EVENT_ID_NEBULAE_CREATED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_STAR)
      if (obj_id > 0) then
        set retval := Execute_Event_Nebulae_Created_Begin(obj_id)
      endif
    EVENT_ID_NEBULAE_DESTROYED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_NEBULAE)
      if (obj_id > 0) then
        set retval := Execute_Event_Nebulae_Destroyed(obj_id)
      endif
    EVENT_ID_BLACK_HOLE_CREATED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_STAR)
      if (obj_id > 0) then
        set retval := Execute_Event_Black_Hole_Created_Begin(obj_id)
      endif
    EVENT_ID_BLACK_HOLE_DESTROYED:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_BLACK_HOLE)
      if (obj_id > 0) then
        set retval := Execute_Event_Black_Hole_Destroyed(obj_id)
      endif
    EVENT_ID_EMPIRE_POINTS_CHANGE:
      set obj_id := Select_Event_Parameter(PARAM_TYPE_PLAYER)
      if (obj_id > 0) then
        set retval := Execute_Event_Empire_Points_Change(obj_id)
      endif
  endcase

  return retval
end

//------------------------------------------------------------------------
// Select_Event_Parameter
//------------------------------------------------------------------------
function Select_Event_Parameter returns long
params
  param_type:                long
vars
  obj_id:                    long := 0
  sobj_list:                 longlist
  loop_count:                long
  list_count:                long
  pick:                      long
begin

  // Create a list of valid objects for the selected parameter
  case param_type
    PARAM_TYPE_SHIP:
      call Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_SHIP, sobj_list, TRUE, FALSE, 0)
    PARAM_TYPE_UNITGROUP:
      call Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_UNITGROUP, sobj_list, TRUE, FALSE, 0)
    PARAM_TYPE_PLANET:
      call Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_PLANET, sobj_list, TRUE, FALSE, 0)
    PARAM_TYPE_WARP_POINT:
      call Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_WARP_POINT, sobj_list, FALSE, FALSE, 0)
    PARAM_TYPE_STAR:
      call Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_STAR, sobj_list, FALSE, FALSE, 0)
    PARAM_TYPE_STORM:
      call Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_STORM, sobj_list, FALSE, FALSE, 0)
    PARAM_TYPE_SYSTEM:
      call Sys_Get_List_Of_Solar_Systems(sobj_list)
    PARAM_TYPE_PLAYER:
      call Sys_Get_List_Of_All_Players(sobj_list)
    PARAM_TYPE_BLACK_HOLE:
      call Sys_Get_List_Of_Black_Holes(sobj_list)
    PARAM_TYPE_NEBULAE:
      call Sys_Get_List_Of_Nebulae(sobj_list)
  endcase

  // Choose the specific target from the list of objects
  set list_count := sobj_list.count()
  if (list_count > 0) then
    set loop_count := 0
    loop
      set loop_count := loop_count + 1
      set pick := Sys_Get_Random_Long(1, list_count)
      set obj_id := sobj_list.get(pick)
      if (not Is_Target_Param_Acceptable(param_type, obj_id)) then
        set obj_id := 0
        call sobj_list.delete(pick)
        set list_count := sobj_list.count()
      endif
      exitwhen (obj_id > 0) or (loop_count > 500) or (list_count <= 0)
    endloop
  endif

  return obj_id
end

//------------------------------------------------------------------------
// Is_Target_Param_Acceptable
//------------------------------------------------------------------------
function Is_Target_Param_Acceptable returns boolean
params
  param_type:                long
  param_id:                  long
vars
  retval:                    boolean := TRUE
  sys_loc:                   long
  sect_loc:                  long
  plr_owner:                 long
  plr:                       long
  event_mod:                 long
  num_players:               long
  param_unit_id:             long
  param_group_type:          string
begin

  // Get the number of players
  set num_players := Sys_Get_Number_Of_Players()

  if (param_type <> PARAM_TYPE_PLAYER) and (param_type <> PARAM_TYPE_SYSTEM) then
    set sys_loc := Sys_Get_Space_Object_System_Location(param_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(param_id)
    set plr_owner := Sys_Get_Space_Object_Owner(param_id)
  endif

  // No high or catastrophic events in a players' home systems
  if (param_type = PARAM_TYPE_PLANET) or (param_type = PARAM_TYPE_STAR) then
    if (lng_Event_Severity >= EVENT_SEVERITY_HIGH) then
      for plr := 1 to num_players do
        if (sys_loc = Sys_Get_Empire_Home_System(plr)) and (sect_loc = Sys_Get_Empire_Home_Sector(plr)) then
          set retval := FALSE
        endif
      endfor
    endif
  endif

  // No mothballed ships
  if (param_type = PARAM_TYPE_SHIP) then
    if Sys_Is_Space_Object_Mothballed(param_id) then
      set retval := FALSE
    endif
  endif

  // Minefields
  if (param_type = PARAM_TYPE_UNITGROUP) then
    if (Sys_Get_Number_Of_Units_In_Space_Sector(plr_owner, "Mine", sys_loc, sect_loc) <= 0) then
      set retval := FALSE
    else
      // Make sure it's mines!
      set param_unit_id := Sys_Get_Space_Object_Cargo_Item_ID(param_id, 1)
      set param_group_type := Sys_Get_Space_Object_Cargo_Item_Unit_Type(param_id, param_unit_id)
      // Check the unit type to make sure its mines
      if (param_group_type = "Mine") then
        // Temp debug output
        call Sys_Debug_Print("Events", "      - It's really a minefield! Object = " + Sys_Get_Space_Object_Name(param_id))
      else
        set retval := FALSE
      endif
    endif
  endif

  // Fate Shrines & Luck
  if (sys_loc > 0) and (retval) then
    set event_mod := Sys_Get_Solar_System_Bad_Event_Avoidance_Percent(sys_loc)
    if (Sys_Get_Random_Long(1, 100) <= event_mod) then
      set retval := FALSE
    endif
  endif

  return retval
end

//------------------------------------------------------------------------
// Give_Message_To_Players
//------------------------------------------------------------------------
function Give_Message_To_Players returns boolean
params
  msg_to_type:               long
  to_plr:                    long
  sys_loc:                   long
  sect_loc:                  long
  msg_title:                 string
  msg_text:                  string
  small_portrait_pic:        string
  large_portrait_pic:        string
  log_type:                  long
vars
  plr_list:                  longlist
  index:                     long
  this_plr:                  long
  plr_count:                 long
  log_cat:                   long
  log_sub_cat:               long
  plr_caused:                long := 0
  debug_str:                 string
begin

  // Setup the log entry
  set log_cat := LOG_CATEGORY_TYPE_EMPIRE_NEWS
  set log_sub_cat := LOG_SUB_CATEGORY_TYPE_EMPIRE_MISC

  // Note the message scope
  case msg_to_type
    MESSAGE_TO_OWNER:
      call plr_list.add(to_plr)
      set debug_str := "Only player " + Sys_Convert_Long_To_String(to_plr) + " affected"
    MESSAGE_TO_SECTOR:
      call Sys_Get_Players_In_Sector_List(plr_list, sys_loc, sect_loc)
      set debug_str := "Only players in the sector affected"
    MESSAGE_TO_SYSTEM:
      call Sys_Get_Players_In_System_List(plr_list, sys_loc)
      set debug_str := "Only players in the system affected"
    MESSAGE_TO_ALL:
      call Sys_Get_All_Players_List(plr_list)
      set debug_str := "All players affected"
  endcase

  // Add executed event to the logs of affected players
  set plr_count := plr_list.count()

  if (plr_count > 0) then
    for index := 1 to plr_count do
      set this_plr := plr_list.get(index)
      call Sys_Add_Empire_Log_Entry(this_plr, sys_loc, sect_loc, msg_title, msg_text, small_portrait_pic, large_portrait_pic, log_type, log_cat, log_sub_cat, plr_caused)
    endfor
  endif

  // Debug output
  call Sys_Debug_Print("Events", msg_title)
  call Sys_Debug_Print("Events", "  - " + debug_str)
  call Sys_Debug_Print("Events", "  - " + msg_text)

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Ship_Damage
//------------------------------------------------------------------------
function Execute_Event_Ship_Damage returns boolean
params
  ship_id:                   long
vars
  dmg_amount:                long
  dmg_type:                  string := "Normal"
  dmg_description:           string := "kT of damage"
  sys_loc:                   long
  sect_loc:                  long
  ship_owner:                long
  ship_name:                 string
  ship_structure:            long
  ship_armor:                long
  ship_shields:              long
  ship_hitpoints:            long
  ship_num_weapons:          long
  ship_movement:             long
  ship_destroyed:            boolean := FALSE
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the target ship's details
  if (ship_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
    set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
    set ship_name := Sys_Get_Space_Object_Name(ship_id)
    set ship_structure := Sys_Get_Space_Object_Total_Tonnage_Structure(ship_id) - Sys_Get_Space_Object_Current_Armor_Structure(ship_id)
    set ship_armor := Sys_Get_Space_Object_Current_Armor_Structure(ship_id)
    set ship_shields := Sys_Get_Space_Object_Current_Shields(ship_id)
    set ship_hitpoints := ship_structure + ship_armor + ship_shields
    set ship_num_weapons := Sys_Get_Space_Object_Number_Of_UnDamaged_Weapons(ship_id)
    set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)

    // Determine the cause and amount of damage
    case Sys_Get_Random_Long(1, 10)
      1:
        if (ship_shields > 0) then
          set event_cause := "An ion storm"
          set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_shields, 4), Sys_Divide_Long(ship_shields, 2))
          set dmg_type := "Shields Only"
          set dmg_description := "shield damage"
        else
          set event_cause := "A security breach"
          set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_hitpoints, 10), Sys_Divide_Long(ship_hitpoints, 5))
        endif
      2:
        set event_cause := "A meteoroid strike"
        set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_hitpoints, 5), Sys_Divide_Long(ship_hitpoints, 2))
      3:
        set event_cause := "A pirate attack"
        set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_hitpoints, 5), Sys_Divide_Long(ship_hitpoints, 2))
      4:
        if (ship_movement > 0) then
          set event_cause := "An engine overload"
          set dmg_amount := Sys_Get_Random_Long(100, 200)
          set dmg_type := "Only Engines"
          set dmg_description := "kT of engine damage"
        else
          set event_cause := "A micrometeoroid storm"
          set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_hitpoints, 10), Sys_Divide_Long(ship_hitpoints, 2))
        endif
      5:
        set event_cause := "A series of ruptured power conduits"
        set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_hitpoints, 5), Sys_Divide_Long(ship_hitpoints, 2))
        set dmg_type := "Skips Shields And Armor"
        set dmg_description := "kT of component damage"
      6:
        if (ship_num_weapons > 0) then
          set event_cause := "A weapon systems malfunction"
          set dmg_amount := Sys_Get_Random_Long(20, ship_num_weapons * 20)
          set dmg_type := "Only Weapons"
          set dmg_description := "kT of weapon systems damage"
        else
          set event_cause := "A comet strike"
          set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_hitpoints, 5), Sys_Divide_Long(ship_hitpoints, 2))
        endif
      7:
        if (ship_shields > 0) then
          set event_cause := "A shield generator overload"
          set dmg_amount := Sys_Get_Random_Long(20, 50)
          set dmg_type := "Only Shield Generators"
          set dmg_description := "kT of shield component damage"
        else
          set event_cause := "A collision with space debris"
          set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_hitpoints, 4), Sys_Divide_Long(ship_hitpoints, 2))
        endif
      8:
        if (ship_num_weapons > 0) then
          set event_cause := "A weapon systems discharge"
          set dmg_amount := Sys_Get_Random_Long(20, ship_num_weapons * 20)
          set dmg_type := "Only Weapons"
          set dmg_description := "kT of weapon systems damage"
        else
          set event_cause := "A comet strike"
          set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_hitpoints, 5), Sys_Divide_Long(ship_hitpoints, 2))
        endif
      9:
        if (ship_movement > 0) then
          set event_cause := "A supply containment failure"
          set dmg_amount := Sys_Get_Random_Long(100, 200)
          set dmg_type := "Only Engines"
          set dmg_description := "kT of engine damage"
        else
          set event_cause := "A number of internal explosions"
          set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_structure, 10), Sys_Divide_Long(ship_structure, 4))
          set dmg_type := "Skips Shields And Armor"
          set dmg_description := "kT of component damage"
        endif
      10:
        set event_cause := "A catastrophic systems failure"
        set dmg_amount := ship_hitpoints + 1000
    endcase

    // Was the ship destroyed?
    if (dmg_amount >= ship_hitpoints) then
      set ship_destroyed := TRUE
    endif

    // Damage the ship
    if (dmg_amount > 0) then
      call Sys_Space_Object_Take_Damage(ship_id, dmg_type, dmg_amount)

      // Log Message to owner
      set log_type := LOG_TYPE_SHIP_DAMAGED
      if (ship_destroyed) then
        set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 2 Title")
        set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 2 Text")
        set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 2 Small Picture Filename")
        set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 2 Large Picture Filename")
      else
        set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 1 Title")
        set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 1 Text")
        set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 1 Small Picture Filename")
        set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 1 Large Picture Filename")
      endif

      set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", ship_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%DamageAmount%]", Sys_Convert_Long_To_String(dmg_amount), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%DamageType%]", dmg_description, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_OWNER, ship_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Ship_Lose_Movement
//------------------------------------------------------------------------
function Execute_Event_Ship_Lose_Movement returns boolean
params
  ship_id:                   long
vars
  move_amount:               long
  ship_max_move:             long
  sys_loc:                   long
  sect_loc:                  long
  ship_owner:                long
  ship_name:                 string
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
  lost_movement:             boolean := FALSE
begin

  // Get the target ship's details
  if (ship_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
    set ship_max_move := Sys_Get_Space_Object_Maximum_Movement(ship_id)
    set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
    set ship_name := Sys_Get_Space_Object_Name(ship_id)

    // How much movement?
    if (ship_max_move > 0) then
      set move_amount := Sys_Get_Random_Long(5, ship_max_move)
    endif

    // Change the movement
    if (move_amount > 0) then
      set lost_movement := Sys_Space_Object_Change_Movement(ship_id, -move_amount)

      // Pick a cause for the movement
      case Sys_Get_Random_Long(1, 4)
        1:
          set event_cause := "An engine malfunction"
        2:
          set event_cause := "A navigation error"
        3:
          set event_cause := "A power loss"
        4:
          set event_cause := "An engine failure"
      endcase

      // Log Message to owner
      set log_type := LOG_TYPE_SHIP_LOSE_MOVEMENT
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 3 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 3 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 3 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 3 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", ship_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%MoveAmount%]", Sys_Convert_Long_To_String(move_amount), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_OWNER, ship_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return lost_movement
end

//------------------------------------------------------------------------
// Execute_Event_Ship_Lose_Supplies
//------------------------------------------------------------------------
function Execute_Event_Ship_Lose_Supplies returns boolean
params
  ship_id:                   long
vars
  sys_loc:                   long
  sect_loc:                  long
  ship_owner:                long
  ship_name:                 string
  ship_curr_supply:          long
  ship_curr_ordnance:        long
  event_title:               string
  event_cause:               string
  item_amt:                  long := 0
  item_name:                 string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
  lost_supplies:             boolean := FALSE
begin

  // Get the target ship's details
  if (ship_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
    set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
    set ship_name := Sys_Get_Space_Object_Name(ship_id)
    set ship_curr_supply := Sys_Get_Space_Object_Current_Supply(ship_id)
    set ship_curr_ordnance := Sys_Get_Space_Object_Current_Ordnance(ship_id)

    // How much ordnance or supply to lose?
    if (Sys_Get_Space_Object_Maximum_Ordnance(ship_id) > 100) and (Sys_Get_Random_Long(1, 2) = 1) then
      set item_amt := Sys_Get_Random_Long(100, ship_curr_ordnance)
      set item_name := "ordnance"
      set event_title := "Ordnance Lost"
      set lost_supplies := Sys_Space_Object_Change_Ordnance(ship_id, -item_amt)
      // Pick a cause for the ordnance lost
      case Sys_Get_Random_Long(1, 3)
        1:
          set event_cause := "An ordnance mishap has occurred"
        2:
          set event_cause := "A bad batch of ordnance had to be jettisoned"
        3:
          set event_cause := "An ordnance containment system failed"
      endcase
    else
      if (ship_curr_supply > 500) then
        set item_amt := Sys_Get_Random_Long(500, ship_curr_supply)
        set item_name := "supplies"
        set event_title := "Supplies Lost"
        set lost_supplies := Sys_Space_Object_Change_Supplies(ship_id, -item_amt)
        // Pick a cause for the movement
        case Sys_Get_Random_Long(1, 3)
          1:
            set event_cause := "A supply leak has occurred"
          2:
            set event_cause := "Supplies were lost"
          3:
            set event_cause := "A supply containment system failed"
        endcase
      endif
    endif

    // Log message to owner
    if (item_amt > 0) then
      set log_type := LOG_TYPE_SHIP_LOSE_SUPPLY
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 4 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 4 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 4 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 4 Large Picture Filename")

      set message_title := Sys_Replace_String(message_title, "[%EventTitle%]", event_title, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", ship_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%ItemAmount%]", Sys_Convert_Long_To_String(item_amt), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%ItemName%]", item_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_OWNER, ship_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return lost_supplies
end

//------------------------------------------------------------------------
// Execute_Event_Ship_Rebels
//------------------------------------------------------------------------
function Execute_Event_Ship_Rebels returns boolean
params
  ship_id:                   long
vars
  sys_loc:                   long
  sect_loc:                  long
  ship_owner:                long
  ship_name:                 string
  loop_count:                long := 0
  plr_index:                 long
  new_owner:                 long
  new_owner_name:            string
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the target ship's details
  if (ship_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
    set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
    set ship_name := Sys_Get_Space_Object_Name(ship_id)

    // Choose a known empire for the ship to join
    loop
      set loop_count := loop_count + 1
      set plr_index := Sys_Get_Random_Long(1, Sys_Get_Number_Of_Players())
      // Choose a new owner
      if Sys_Empire_Politics_Is_Player_Known(sys_long_Player_ID, plr_index) and (ship_owner <> plr_index) then
        set new_owner := plr_index
        set new_owner_name := Sys_Empire_Get_Empire_Name(plr_index)
      endif
      exitwhen (new_owner > 0) or (loop_count > 20)
    endloop

    // Choose the event cause
    case Sys_Get_Random_Long(1, 4)
      1:
        set event_cause := "A crew rebellion aboard"
      2:
        set event_cause := "A hostile takeover of"
      3:
        set event_cause := "A crew mutiny on"
      4:
        set event_cause := "An unknown event on"
    endcase

    // Change the ownership
   if Sys_Space_Object_Set_To_New_Owner(ship_id, new_owner) then
      // Log Message to owner
      set log_type := LOG_TYPE_SHIP_REBEL
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 5 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 5 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 5 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 5 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%NewEmpireName%]", new_owner_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", ship_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_OWNER, ship_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Ship_Experience_Change
//------------------------------------------------------------------------
function Execute_Event_Ship_Experience_Change returns boolean
params
  ship_id:                   long
vars
  sys_loc:                   long
  sect_loc:                  long
  ship_owner:                long
  ship_name:                 string
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the target ship's details
  if (ship_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
    set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
    set ship_name := Sys_Get_Space_Object_Name(ship_id)

    // Choose the event cause
    case Sys_Get_Random_Long(1, 3)
      1:
        set event_cause := "Due to a computer error"
      2:
        set event_cause := "Due to mass amnesia"
      3:
        set event_cause := "Due to a miscommunication"
    endcase

    // Change the experience
    call Sys_Space_Object_Change_Experience(ship_id, -10000)

    // Log Message to owner
    set log_type := LOG_TYPE_SHIP_EXPERIENCE_CHANGE
    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 6 Title")
    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 6 Text")
    set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 6 Small Picture Filename")
    set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 6 Large Picture Filename")

    set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", ship_name, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

    call Give_Message_To_Players(MESSAGE_TO_OWNER, ship_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Ship_Cargo_Damage
//------------------------------------------------------------------------
function Execute_Event_Ship_Cargo_Damage returns boolean
params
  ship_id:                   long
vars
  sys_loc:                   long
  sect_loc:                  long
  ship_owner:                long
  ship_name:                 string
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Attempt to destroy the ship's cargo
  if (ship_id > 0) then
    if Sys_Does_Space_Object_Cargo_Have_Non_Supply_Ordnance_Item(ship_id) then
      // Get the target ship's details
      set sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
      set sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
      set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
      set ship_name := Sys_Get_Space_Object_Name(ship_id)

      // Choose a cause for the loss of cargo
      case Sys_Get_Random_Long(1, 3)
        1:
          set event_cause := "A pirate attack against the"
        2:
          set event_cause := "A cargo bay malfunction on the"
        3:
          set event_cause := "An explosion in the cargo hold of the"
      endcase

      // Attempt to remove all the cargo
      if Sys_Space_Object_Delete_Cargo(ship_id) then
        // Log Message to owner
        set log_type := LOG_TYPE_SHIP_CARGO_DAMAGE
        set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 7 Title")
        set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 7 Text")
        set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 7 Small Picture Filename")
        set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 7 Large Picture Filename")

        set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
        set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", ship_name, TRUE, TRUE)
        set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
        set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

        call Give_Message_To_Players(MESSAGE_TO_OWNER, ship_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
      endif
    else
      // If no other cargo items, damage supplies and ordnance instead
      call Execute_Event_Ship_Lose_Supplies(ship_id)
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Ship_Orders_Change
//------------------------------------------------------------------------
function Execute_Event_Ship_Orders_Change returns boolean
params
  ship_id:                   long
vars
  sys_loc:                   long
  sect_loc:                  long
  target_sys_loc:            long
  target_sect_loc:           long
  ship_owner:                long
  ship_name:                 string
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the target ship's details
  if (ship_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
    set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
    set ship_name := Sys_Get_Space_Object_Name(ship_id)

    // Choose a cause
    case Sys_Get_Random_Long(1, 4)
      1:
        set event_cause := "A navigation error has resulted in the wrong orders for"
      2:
        set event_cause := "A miscommunication has caused the wrong orders to be issued to"
      3:
        set event_cause := "It appears a false set of orders was received by"
      4:
        set event_cause := "A set of false orders was sent to"
    endcase

    // Clear the ship's previous orders
    call Sys_Space_Object_Clear_Orders(ship_id)
    call Sys_Space_Object_Clear_Fleet(ship_id)

    // Give the ship new orders
    set target_sys_loc := Sys_Get_Random_Long(1, Sys_Get_Number_Of_Solar_Systems())
    set target_sect_loc := Sys_Get_Random_Sector()
    call Sys_Give_Space_Object_Order_Moveto(ship_id, target_sys_loc, target_sect_loc)

    // Log Message to owner
    set log_type := LOG_TYPE_SHIP_ORDERS_CHANGE
    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 8 Title")
    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 8 Text")
    set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 8 Small Picture Filename")
    set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 8 Large Picture Filename")

    set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", ship_name, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

    call Give_Message_To_Players(MESSAGE_TO_OWNER, ship_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Ship_Moved
//------------------------------------------------------------------------
function Execute_Event_Ship_Moved returns boolean
params
  ship_id:                   long
vars
  sys_loc:                   long
  sect_loc:                  long
  target_sys_loc:            long
  target_sect_loc:           long
  ship_owner:                long
  ship_name:                 string
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the ship's details
  if (ship_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
    set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
    set ship_name := Sys_Get_Space_Object_Name(ship_id)

    // Clear the ship's orders
    call Sys_Space_Object_Clear_Orders(ship_id)
    call Sys_Space_Object_Clear_Fleet(ship_id)

    // Choose a cause for this event
    case Sys_Get_Random_Long(1, 2)
      1:
        set event_cause := "A freak spatial anomaly has"
      2:
        set event_cause := "Some sort of transient warp point appeared and"
    endcase

    // Choose a target system
    set target_sys_loc := Sys_Get_Random_Long(1, Sys_Get_Number_Of_Solar_Systems())
    set target_sect_loc := Sys_Get_Random_Empty_Sector(target_sys_loc)

    if (target_sys_loc > 0) and (target_sect_loc > 0) then
      call Sys_Set_Space_Object_Position(ship_id, target_sys_loc, target_sect_loc)

      // Log Message to owner
      set log_type := LOG_TYPE_SHIP_MOVED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 9 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 9 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 9 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 9 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", ship_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%DestSystemName%]", Sys_Get_Solar_System_Name(target_sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%DestSectorLoc%]", Sys_Get_Sector_Coordinates(target_sect_loc), TRUE, TRUE)
 
      call Give_Message_To_Players(MESSAGE_TO_OWNER, ship_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Minefield_Damage
//------------------------------------------------------------------------
function Execute_Event_Minefield_Damage returns boolean
params
  sobj_id:                   long
vars
  num_mines:                 long
  num_mines_left:            long
  num_mines_destroyed:       long
  sobj_structure:            long
  dmg_amount:                long
  dmg_pct:                   long
  mines_destroyed:           boolean := FALSE
  sys_loc:                   long
  sect_loc:                  long
  sobj_owner:                long
  sobj_name:                 string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the target Empire's minefield details
  if (sobj_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(sobj_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(sobj_id)
    set sobj_owner := Sys_Get_Space_Object_Owner(sobj_id)
    set sobj_name := Sys_Get_Space_Object_Name(sobj_id)
    set sobj_structure := Sys_Get_Space_Object_Total_Tonnage_Structure(sobj_id)
    set num_mines := Sys_Get_Number_Of_Units_In_Space_Sector(sobj_owner, "Mine", sys_loc, sect_loc)
    set dmg_pct := Sys_Get_Random_Long(10, 120)

    // Choose a damage amount between 10~120% of the target minefield structure
    set dmg_amount := Sys_Trunc(dmg_pct * sobj_structure / 100)

    // Temp debug output
    call Sys_Debug_Print("Events", "      - # Mines = " + Sys_Convert_Long_To_String(num_mines))
    call Sys_Debug_Print("Events", "      - Structure = " + Sys_Convert_Long_To_String(sobj_structure))
    call Sys_Debug_Print("Events", "      - Damage % = " + Sys_Convert_Long_To_String(dmg_pct))
    call Sys_Debug_Print("Events", "      - Actual damage = " + Sys_Convert_Long_To_String(dmg_amount))

    // Apply normal damage to the target Empire's minefield
    if (dmg_amount > 0) then
      call Sys_Space_Object_Take_Damage(sobj_id, "Normal", dmg_amount)

      set num_mines_left := Sys_Get_Number_Of_Units_In_Space_Sector(sobj_owner, "Mine", sys_loc, sect_loc)
      set num_mines_destroyed := num_mines - num_mines_left
      // Debug output
      call Sys_Debug_Print("Events", "      - # Mines left = " + Sys_Convert_Long_To_String(num_mines_left))

      if (num_mines_left = 0) then
        set mines_destroyed := TRUE
      endif

      // --- Log Message to owner --------------------------------------------------------------
      set log_type := LOG_TYPE_EVENT
      if (mines_destroyed) then
        // Complete detonation
        set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 40 Title")
        set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 40 Text")
        set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 40 Small Picture Filename")
        set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 40 Large Picture Filename")
      else
        // Partial detonation
        set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 39 Title")
        set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 39 Text")
        set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 39 Small Picture Filename")
        set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 39 Large Picture Filename")
      endif
      // Replacement text
      set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", sobj_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%DamageAmount%]", Sys_Convert_Long_To_String(num_mines_destroyed), TRUE, TRUE)
      // Log message
      call Give_Message_To_Players(MESSAGE_TO_OWNER, sobj_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return (sobj_id > 0)
end

//------------------------------------------------------------------------
// Execute_Event_Planet_Conditions_Change
//------------------------------------------------------------------------
function Execute_Event_Planet_Conditions_Change returns boolean
params
  planet_id:                 long
vars
  sys_loc:                   long
  sect_loc:                  long
  conditions_change:         real
  planet_owner:              long
  planet_name:               string
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the planet's details
  if (planet_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
    set planet_owner := Sys_Get_Space_Object_Owner(planet_id)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)

    // Choose the event cause and amount
    case Sys_Get_Random_Long(1, 5)
      1:
        set event_cause := "The conditions have improved"
        set conditions_change := Sys_Get_Random_Long(1, 5 + lng_Event_Severity) / 10
        set msg_small_pic := "Event_PlanetConditionImproved.jpg"
        set msg_large_pic := "LargePortrait_Event_PlanetConditionImproved.jpg"
      2:
        set event_cause := "A reduction in atmospheric turbulence has resulted in better conditions"
        set conditions_change := Sys_Get_Random_Long(1, 5 + lng_Event_Severity) / 10
        set msg_small_pic := "Event_PlanetConditionImproved.jpg"
        set msg_large_pic := "LargePortrait_Event_PlanetConditionImproved.jpg"
      3:
        set event_cause := "A passing cosmic storm has damaged the conditions"
        set conditions_change := -Sys_Get_Random_Long(1, 5 + lng_Event_Severity) / 10
        set msg_small_pic := "Event_PlanetConditionWorsened.jpg"
        set msg_large_pic := "LargePortrait_Event_PlanetConditionWorsened.jpg"
      4:
        set event_cause := "A burst of cosmic radiation has damaged the conditions"
        set conditions_change := -Sys_Get_Random_Long(1, 5 + lng_Event_Severity) / 10
        set msg_small_pic := "Event_PlanetConditionWorsened.jpg"
        set msg_large_pic := "LargePortrait_Event_PlanetConditionWorsened.jpg"
      5:
        set event_cause := "A meteorite impact has caused the conditions to deteriorate"
        set conditions_change := -Sys_Get_Random_Long(1, 5 + lng_Event_Severity) / 10
        set msg_small_pic := "Event_PlanetConditionWorsened.jpg"
        set msg_large_pic := "LargePortrait_Event_PlanetConditionWorsened.jpg"
    endcase

    // Set New Conditions
    call Sys_Change_Planet_Conditions(planet_id, conditions_change)

    // Log Message to owner
    set log_type := LOG_TYPE_PLANET_CONDITION_CHANGE
    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 10 Title")
    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 10 Text")

    set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

    call Give_Message_To_Players(MESSAGE_TO_OWNER, planet_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Planet_Value_Change
//------------------------------------------------------------------------
function Execute_Event_Planet_Value_Change returns boolean
params
  planet_id:                 long
vars
  sys_loc:                   long
  sect_loc:                  long
  min_change:                long
  org_change:                long
  rad_change:                long
  planet_owner:              long
  planet_name:               string
  event_cause:               string
  effect_amt:                string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the planet's details
  if (planet_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
    set planet_owner := Sys_Get_Space_Object_Owner(planet_id)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)

    // Choose the event cause and amount
    case Sys_Get_Random_Long(1, 6)
      1:
        set event_cause := "The mineral value has been overestimated"
        set min_change := -Sys_Get_Random_Long(5, 10 + (lng_Event_Severity * 5))
      2:
        set event_cause := "A volcanic eruption has increased the mineral value"
        set min_change := Sys_Get_Random_Long(5, 10 + (lng_Event_Severity * 5))
      3:
        set event_cause := "The organics value has been overestimated"
        set org_change := -Sys_Get_Random_Long(5, 10 + (lng_Event_Severity * 5))
      4:
        set event_cause := "A new discovery has increased the organics value"
        set org_change := Sys_Get_Random_Long(5, 10 + (lng_Event_Severity * 5))
      5:
        set event_cause := "The radioactives value has been overestimated"
        set rad_change := -Sys_Get_Random_Long(5, 10 + (lng_Event_Severity * 5))
      6:
        set event_cause := "A meteor strike has increased the radioactives value"
        set rad_change := Sys_Get_Random_Long(5, 10 + (lng_Event_Severity * 5))
    endcase

    // Choose the event picture
    if ((min_change + org_change + rad_change) > 0) then
      set msg_small_pic := "Event_PlanetValueImproved.jpg"
      set msg_large_pic := "LargePortrait_Event_PlanetValueImproved.jpg"
    else
      set msg_small_pic := "Event_PlanetValueWorsens.jpg"
      set msg_large_pic := "LargePortrait_Event_PlanetValueWorsens.jpg"
    endif

    // If this is a finite resource game, adjust the amount of resources lost/gained
    if Sys_Is_Finite_Resource_Game() then
      set min_change := min_change * 10000
      set org_change := org_change * 10000
      set rad_change := rad_change * 10000
      set effect_amt := Sys_Convert_Long_To_String(min_change + org_change + rad_change) + "kT"
    else
      set effect_amt := Sys_Convert_Long_To_String(min_change + org_change + rad_change) + "%"
    endif

    // Change the planet's value
    call Sys_Change_Planet_Value(planet_id, min_change, RESOURCE_TYPE_MINERALS)
    call Sys_Change_Planet_Value(planet_id, org_change, RESOURCE_TYPE_ORGANICS)
    call Sys_Change_Planet_Value(planet_id, rad_change, RESOURCE_TYPE_RADIOACTIVES)

    // Log Message to owner
    set log_type := LOG_TYPE_PLANET_VALUE_CHANGE
    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 11 Title")
    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 11 Text")

    set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%EffectAmount%]", effect_amt, TRUE, TRUE)

    call Give_Message_To_Players(MESSAGE_TO_OWNER, planet_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Planet_Population_Change
//------------------------------------------------------------------------
function Execute_Event_Planet_Population_Change returns boolean
params
  planet_id:                 long
vars
  sys_loc:                   long
  sect_loc:                  long
  pop_change:                long
  max_pop:                   long
  planet_owner:              long
  planet_name:               string
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the planet's details
  if (planet_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
    set planet_owner := Sys_Get_Space_Object_Owner(planet_id)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)

    // Set Population Change
    set pop_change := Sys_Get_Random_Long(10, 50 + (lng_Event_Severity * 50))
    set max_pop := Sys_Get_Planet_Population(planet_id)

    if (pop_change > max_pop) then
      set pop_change := max_pop - Sys_Get_Random_Long(5, 10)
    endif

    call Sys_Change_Planet_Population(planet_id, -pop_change)

    // Pick the disaster type
    if Sys_Is_Planet_Domed(planet_id) then
      // Domed planets
      case Sys_Get_Random_Long(1, 5)
        1:
          set event_cause := "A powerful earthquake has ruptured many protective domes on"
        2:
          set event_cause := "A meteor struck our colony on"
        3:
          set event_cause := "A surge of cosmic radiation irradiated the surface of"
        4:
          set event_cause := "Several of our protective domes have collapsed on"
        5:
          set event_cause := "A life support failure across several domes on"
      endcase
    else
      // Breathable planets
      case Sys_Get_Random_Long(1, 3)
        1:
          set event_cause := "A powerful earthquake occurred on"
        2:
          set event_cause := "A meteor struck our colony on"
        3:
          set event_cause := "A surge of cosmic radiation irradiated the surface of"
      endcase
    endif

    // Log Message to owner
    set log_type := LOG_TYPE_PLANET_POP_CHANGE
    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 12 Title")
    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 12 Text")
    set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 12 Small Picture Filename")
    set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 12 Large Picture Filename")

    set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%Amount%]", Sys_Convert_Long_To_String(pop_change), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

    call Give_Message_To_Players(MESSAGE_TO_OWNER, planet_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Planet_Population_Happiness_Change
//------------------------------------------------------------------------
function Execute_Event_Planet_Population_Happiness_Change returns boolean
params
  planet_id:                     long
vars
  sys_loc:                       long
  sect_loc:                      long
  happiness_change:              long
  planet_owner:                  long
  planet_name:                   string
  event_cause:                   string
  message_title:                 string
  message_text:                  string
  msg_small_pic:                 string
  msg_large_pic:                 string
  log_type:                      long
begin

  // Get the planet's details
  if (planet_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
    set planet_owner := Sys_Get_Space_Object_Owner(planet_id)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)

    // Choose the event cause
    if Sys_Is_Planet_Domed(planet_id) then
      // Domed planets
      case Sys_Get_Random_Long(1, 3)
        1:
          set event_cause := "rampant corruption in the local administration"
        2:
          set event_cause := "poor maintenance of the habitat domes"
        3:
          set event_cause := "the substandard living conditions"
      endcase
    else
      // Breathable planets
      case Sys_Get_Random_Long(1, 3)
        1:
          set event_cause := "rampant corruption in the local administration"
        2:
          set event_cause := "recent events"
        3:
          set event_cause := "the substandard living conditions"
      endcase
    endif

    if Sys_Is_Planet_Effected_By_Happiness(planet_id) then
      // Reduce the planet's population happiness
      set happiness_change := Sys_Get_Random_Long(10, 50)
      call Sys_Change_Planet_Population_Happiness(planet_id, happiness_change)

      // Log Message to owner
      set log_type := LOG_TYPE_PLANET_POP_ANGER_CHANGE
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 13 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 13 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 13 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 13 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_OWNER, planet_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Planet_Population_Riot
//------------------------------------------------------------------------
function Execute_Event_Planet_Population_Riot returns boolean
params
  planet_id:                 long
  bypass_event:              boolean
vars
  sys_loc:                   long
  sect_loc:                  long
  planet_owner:              long
  planet_name:               string
  planet_happiness:          long
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the planet's details
  if (planet_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
    set planet_owner := Sys_Get_Space_Object_Owner(planet_id)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)
    set planet_happiness := Sys_Get_Planet_Happiness(planet_id)

    if (planet_happiness < 60) and Sys_Is_Planet_Effected_By_Happiness(planet_id) then
      // Set Population To Riot
      call Sys_Set_Planet_Population_To_Riot(planet_id)

      // Choose the event cause
      if (bypass_event) then
        set event_cause := "high levels of disloyalty amongst the alien population."
      else
        case Sys_Get_Random_Long(1, 3)
          1:
            set event_cause := "the high levels of taxation on the colony"
          2:
            set event_cause := "the deplorable living conditions"
          3:
            set event_cause := "corruption in the colony administration"
        endcase
      endif

      // Log Message to owner
      set log_type := LOG_TYPE_PLANET_POP_RIOTING
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 14 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 14 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 14 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 14 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_OWNER, planet_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Planet_Population_Rebel
//------------------------------------------------------------------------
function Execute_Event_Planet_Population_Rebel returns boolean
params
  planet_id:                 long
  bypass_event:              boolean
vars
  sys_loc:                   long
  sect_loc:                  long
  planet_owner:              long
  planet_name:               string
  planet_happiness:          long
  cargo_item_count:          long
  cargo_item_index:          long
  cargo_item_id:             long
  cargo_item_unit_type:      string
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get the planet's details
  if (planet_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
    set planet_owner := Sys_Get_Space_Object_Owner(planet_id)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)
    set planet_happiness := Sys_Get_Planet_Happiness(planet_id)

    // Only unhappy planets or planets belonging to the G'Urak can rebel
    if (planet_happiness < 10 and Sys_Is_Planet_Effected_By_Happiness(planet_id)) then
      // Remove all unit cargo
      set cargo_item_count := Sys_Get_Space_Object_Cargo_Item_Count(planet_id)
      // Go through the planet's cargo list, scrapping any item that is a unit
      if (cargo_item_count > 0) then
        loop
          set cargo_item_index := cargo_item_index + 1
          set cargo_item_id := Sys_Get_Space_Object_Cargo_Item_ID(planet_id, cargo_item_index)
          set cargo_item_unit_type := Sys_Get_Space_Object_Cargo_Item_Unit_Type(planet_id, cargo_item_id)
          // Only scrap items that are units
          if (Sys_Length_String(cargo_item_unit_type) > 0) then
            call Sys_Space_Object_Scrap_Cargo(planet_id, cargo_item_id)
            set cargo_item_count := cargo_item_count - 1
            set cargo_item_index := cargo_item_index - 1
            // Debug output
            call Sys_Debug_Print("Events", "      - Planet cargo item scrapped ( " + cargo_item_unit_type + ")")
          endif
          exitwhen (cargo_item_index <= 0) or (cargo_item_index >= cargo_item_count)
        endloop
      endif

      // Set the planet as a new empire
      call Sys_Space_Object_Set_To_New_Owner(planet_id, 0)

      if (bypass_event) then
        set event_cause := " The alien population had become very disloyal."
      endif

      // Log Message to owner
      set log_type := LOG_TYPE_PLANET_POP_REBEL
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 15 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 15 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 15 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 15 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_OWNER, planet_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Planet_Cargo_Damage
//------------------------------------------------------------------------
function Execute_Event_Planet_Cargo_Damage returns boolean
params
  planet_id:                 long
vars
  sys_loc:                   long
  sect_loc:                  long
  planet_owner:              long
  planet_name:               string
  planet_pop:                long
  min_dmg:                   long
  max_dmg:                   long
  dmg_amt:                   long
  pop_amt:                   long
  planet_structure:          long
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Damage a colony
  if (planet_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
    set planet_owner := Sys_Get_Space_Object_Owner(planet_id)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)
    set planet_pop := Sys_Get_Planet_Population(planet_id)
    set planet_structure := Sys_Get_Space_Object_Total_Tonnage_Structure(planet_id)
    set min_dmg := Sys_Divide_Long(planet_structure, 25)
    set max_dmg := Sys_Divide_Long(planet_structure, (20 - lng_Event_Severity * 5))

    // Choose the event cause
    if Sys_Is_Planet_Domed(planet_id) then
      // Domed planets
      case Sys_Get_Random_Long(1, 4)
        1:
          set event_cause := "has suffered a massive containment failure"
        2:
          set event_cause := "was hit by widespread tectonic activity that has collapsed domes across the planet"
        3:
          set event_cause := "was hit by multiple impactors"
        4:
          set event_cause := "was the target of a terrorist attack"
      endcase
    else
      case Sys_Get_Random_Long(1, 3)
        1:
          set event_cause := "was hit by a multiple impactors"
        2:
          set event_cause := "was struck by a massive earthquake"
        3:
          set event_cause := "was the target of a terrorist attack"
      endcase
    endif

    // Determine the amount of damage
    set dmg_amt := Sys_Get_Random_Long(min_dmg, max_dmg)
    set pop_amt := Sys_Divide_Long(dmg_amt, 100)

    if (pop_amt > planet_pop) then
      set pop_amt := Sys_Divide_Long(pop_amt, 2)
    endif

    if (dmg_amt > 0) then
      call Sys_Change_Planet_Population(planet_id, -pop_amt)
      call Sys_Space_Object_Take_Damage(planet_id, "Normal", dmg_amt)

      // Log Message to owner
      set log_type := LOG_TYPE_PLANET_CARGO_DAMAGE
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 16 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 16 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 16 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 16 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%DamageAmount%]", Sys_Convert_Long_To_String(dmg_amt), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%PopulationAmount%]", Sys_Convert_Long_To_String(pop_amt), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_OWNER, planet_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Function Execute_Event_Empire_Points_Change
//------------------------------------------------------------------------
function Execute_Event_Empire_Points_Change returns boolean
params
  plr_id:                    long
vars
  min_amt:                   long
  org_amt:                   long
  rad_amt:                   long
  max_min_amt:               long
  max_org_amt:               long
  max_rad_amt:               long
  event_title:               string
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Note the severity level
  set lng_event_severity := Sys_Game_Settings_Get_External_Events_Severity() + 1

  if (plr_id > 0) then
    set min_amt := Sys_Get_Random_Long(1, 5) * 1000 * lng_Event_Severity
    set org_amt := Sys_Get_Random_Long(1, 5) * 1000 * lng_Event_Severity
    set rad_amt := Sys_Get_Random_Long(1, 5) * 1000 * lng_Event_Severity

    set max_min_amt := Sys_Get_Empire_Current_Points(plr_id, POINT_TYPE_MINERALS)
    set max_org_amt := Sys_Get_Empire_Current_Points(plr_id, POINT_TYPE_ORGANICS)
    set max_rad_amt := Sys_Get_Empire_Current_Points(plr_id, POINT_TYPE_RADIOACTIVES)

    // Choose the event cause
    case Sys_Get_Random_Long(1, 6)
      1:
        set event_title := "Pirates!"
        set event_cause := "Pirate raids against our resource freighters in the last month has decreased our resources"
      2:
        set event_title := "Resources Lost"
        set event_cause := "Several resource freighters in transit to our Spaceports have gone missing in the last month"
      3:
        set event_title := "Pirates!"
        set event_cause := "Pirate activity is suspected to have claimed several resource freighters in the past month"
      4:
        set event_title := "Resources Lost"
        set event_cause := "Two resource freighters collided near one of our colonies"
      5:
        set event_title := "Resources Lost"
        set event_cause := "A containment failure in one of our resource storage facilities has decreased our resource stores"
      6:
        set event_title := "Resources Lost"
        set event_cause := "An error in our resource storage accounting has inflated our resource levels"
    endcase

    // Don't take more resources they are available
    if (min_amt > max_min_amt) then
      set min_amt := 0
    endif
    if (org_amt > max_org_amt) then
      set org_amt := 0
    endif
    if (rad_amt > max_rad_amt) then
      set rad_amt := 0
    endif

    // Reduce the resource storage amounts
    call Sys_Change_Empire_Points(plr_id, -min_amt, -org_amt, -rad_amt)

    // Log Message to owner
    set log_type := LOG_TYPE_POINTS_CHANGE
    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 31 Title")
    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 31 Text")
    set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 31 Small Picture Filename")
    set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 31 Large Picture Filename")

    set message_title := Sys_Replace_String(message_title, "[%EventTitle%]", event_title, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%MineralsAmount%]", Sys_Convert_Long_To_String(min_amt), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%OrganicsAmount%]", Sys_Convert_Long_To_String(org_amt), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%RadioactivesAmount%]", Sys_Convert_Long_To_String(rad_amt), TRUE, TRUE)

    call Give_Message_To_Players(MESSAGE_TO_OWNER, plr_id, 0, 0, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Planet_Plague_Created
//------------------------------------------------------------------------
function Execute_Event_Planet_Plague_Created returns boolean
params
  planet_id:                 long
vars
  sys_loc:                   long
  sect_loc:                  long
  planet_owner:              long
  planet_name:               string
  plague_level:              long
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Choose a random planet to plague
  if (planet_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
    set planet_owner := Sys_Get_Space_Object_Owner(planet_id)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)

    // Plague
    set plague_level := Sys_Get_Random_Long(1, 3)

    if (plague_level > 0) then
      call Sys_Set_Planet_Plague_Level(planet_id, plague_level)

      // Log Message to owner
      set log_type := LOG_TYPE_PLANET_PLAGUED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 17 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 17 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 17 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 17 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_OWNER, planet_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Planet_Plague_Cured
//------------------------------------------------------------------------
function Execute_Event_Planet_Plague_Cured returns boolean
params
  planet_id:                 long
vars
  sys_loc:                   long
  sect_loc:                  long
  planet_owner:              long
  planet_name:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Choose the planet to cure a plague on
  if (planet_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
    set planet_owner := Sys_Get_Space_Object_Owner(planet_id)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)

    call Sys_Set_Planet_Plague_Level(planet_id, 0)

    // Log Message to owner
    set log_type := LOG_TYPE_PLANET_PLAGUE_CURED
    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 18 Title")
    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 18 Text")
    set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 18 Small Picture Filename")
    set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 18 Large Picture Filename")

    set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

    call Give_Message_To_Players(MESSAGE_TO_OWNER, planet_owner, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Function Execute_Event_Planet_Created
//------------------------------------------------------------------------
function Execute_Event_Planet_Created returns boolean
params
  sys_id:                    long
vars
  planet_created:            boolean := FALSE
  new_planet_id:             long
  sys_loc:                   long
  sect_loc:                  long
  planet_name:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Create a new random planet
  if (sys_id > 0) then
    set sect_loc := Sys_Get_Random_Empty_Sector(sys_id)
    set planet_created := Sys_Create_Planet(sys_id, sect_loc, "")

    if (planet_created) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_PLANET_CREATED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 19 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 19 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 19 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 19 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return planet_created
end

//------------------------------------------------------------------------
// Function Execute_Event_Planet_Destroyed
//------------------------------------------------------------------------
function Execute_Event_Planet_Destroyed returns boolean
params
  planet_id:                 long
vars
  planet_destroyed:          boolean := FALSE
  sys_loc:                   long
  sect_loc:                  long
  planet_name:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Choose a planet to destroy
  if (planet_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)
    set planet_destroyed := Sys_Destroy_Planet(planet_id)

    if (planet_destroyed) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_PLANET_DESTROYED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 20 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 20 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 20 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 20 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%PlanetName%]", planet_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return planet_destroyed
end

//------------------------------------------------------------------------
// Function Execute_Event_Star_Created
//------------------------------------------------------------------------
function Execute_Event_Star_Created returns boolean
params
  sys_id:                    long
vars
  star_created:              boolean := FALSE
  new_star_id:               long
  sys_loc:                   long
  sect_loc:                  long
  star_name:                 string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Create a new star
  if (sys_id > 0) then
    set sect_loc := Sys_Get_Random_Empty_Sector(sys_id)
    set star_created := Sys_Create_Star(sys_id, sect_loc, "")

    if (star_created) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_STAR_CREATED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 21 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 21 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 21 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 21 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%StarName%]", star_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return star_created
end

//------------------------------------------------------------------------
// Function Execute_Warp_Point_Closed
//------------------------------------------------------------------------
function Execute_Event_Warp_Point_Closed returns boolean
params
  wp_id:                     long
vars
  wp_closed:                 boolean := FALSE
  sys_loc:                   long
  sect_loc:                  long
  wp_name:                   string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Close a random warp point
  if (wp_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(wp_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(wp_id)
    set wp_name := Sys_Get_Space_Object_Name(wp_id)

    // Close the warp point
    set wp_closed := Sys_Close_Warp_Point(wp_id)

    if (wp_closed) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_WP_CLOSED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 23 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 23 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 23 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 23 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%WarpPointName%]", wp_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return wp_closed
end

//------------------------------------------------------------------------
// Function Execute_Event_Warp_Point_Opened
//------------------------------------------------------------------------
function Execute_Event_Warp_Point_Opened returns boolean
params
  sys_id:                    long
vars
  wp_created:                boolean := FALSE
  new_wp_id:                 long
  sys_loc:                   long
  sect_loc:                  long
  dest_sys:                  long
  dest_sect:                 long
  wp_name:                   string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Create a random warp point
  if (sys_id > 0) then
    set sect_loc := Sys_Get_Random_Empty_Sector(sys_id)
    loop
      set dest_sys := Sys_Get_Random_Long(1, Sys_Get_Number_Of_Solar_Systems())
      exitwhen (dest_sys <> sys_id)
    endloop
    set dest_sect := Sys_Get_Random_Empty_Sector(dest_sys)
    set wp_created := Sys_Open_Warp_Point(sys_id, sect_loc, dest_sys, dest_sect, "")

    if (wp_created) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_WP_OPENED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 24 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 24 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 24 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 24 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%WarpPointName%]", wp_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return wp_created
end

//------------------------------------------------------------------------
// Function Execute_Event_Storm_Created
//------------------------------------------------------------------------
function Execute_Event_Storm_Created returns boolean
params
  sys_id:                    long
vars
  storm_created:             boolean := FALSE
  new_storm_id:              long
  sect_loc:                  long
  storm_name:                string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Create a random storm
    if (sys_id > 0) then
      set sect_loc := Sys_Get_Random_Empty_Sector(sys_id)
      set storm_created := Sys_Create_Storm(sys_id, sect_loc, "")

    if (storm_created) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_STORM_CREATED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 25 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 25 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 25 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 25 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%StormName%]", storm_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_id), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_id, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return storm_created
end

//------------------------------------------------------------------------
// Function Execute_Event_Storm_Destroyed
//------------------------------------------------------------------------
function Execute_Event_Storm_Destroyed returns boolean
params
  storm_id:                  long
vars
  storm_destroyed:           boolean := FALSE
  sys_loc:                   long
  sect_loc:                  long
  storm_name:                string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Destroy a random storm
  if (storm_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(storm_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(storm_id)
    set storm_name := Sys_Get_Space_Object_Name(storm_id)

    set storm_destroyed := Sys_Destroy_Storm(storm_id)

    if (storm_destroyed) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_STORM_DESTROYED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 26 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 26 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 26 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 26 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%StormName%]", storm_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return storm_destroyed
end

//------------------------------------------------------------------------
// Function Execute_Event_Nebulae_Destroyed
//------------------------------------------------------------------------
function Execute_Event_Nebulae_Destroyed returns boolean
params
  sys_id:                    long
vars
  nebulae_destroyed:         boolean := FALSE
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Destroy a random nebulae
  if (sys_id > 0) then
    set nebulae_destroyed := Sys_Destroy_Nebulae(sys_id)

    if (nebulae_destroyed) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_NEBULAE_DESTROYED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 28 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 28 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 28 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 28 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_id), TRUE, TRUE)
  
      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_id, 0, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return nebulae_destroyed
end

//------------------------------------------------------------------------
// Function Execute_Event_Black_Hole_Destroyed
//------------------------------------------------------------------------
function Execute_Event_Black_Hole_Destroyed returns boolean
params
  sys_id:                    long
vars
  black_hole_destroyed:      boolean := FALSE
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Destroy a random black hole
  if (sys_id > 0) then
    set black_hole_destroyed := Sys_Destroy_Black_Hole(sys_id)

    if (black_hole_destroyed) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_BLACK_HOLE_DESTROYED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 30 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 30 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 30 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 30 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_id), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_id, 0, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif 
  endif

  return black_hole_destroyed
end

//------------------------------------------------------------------------
// Timed_Events
//------------------------------------------------------------------------
function Timed_Events returns boolean
params
vars
  sys_count:                 long
  num_timed_events:          long
  index:                     long
  sub_index:                 long
  time_remaining:            long
  event_id:                  long
  obj_id:                    long
  sys_loc:                   long
  sect_loc:                  long
  storage_index:             long
  sub_storage_index1:        long
  sub_storage_index2:        long
begin

  // Timed events are stored after the system chokepoint scores in the events memory storage
  set sys_count := Sys_Get_Number_Of_Solar_Systems()

  // Get the number of timed events in progress
  set num_timed_events := Sys_Get_Event_Storage_Long(sys_count + 1)

  // Reduce the time remaining or if at 0 time, execute the timed event
  if (num_timed_events > 0) then
    for index := 1 to num_timed_events do
      set storage_index := BASE_EVENT_RECORD_LENGTH + (index * TIMED_EVENT_RECORD_LENGTH)

      set time_remaining := Sys_Get_Event_Storage_Long(storage_index + 0)
      set event_id := Sys_Get_Event_Storage_Long(storage_index + 1)
      set obj_id := Sys_Get_Event_Storage_Long(storage_index + 2)
      set sys_loc := Sys_Get_Event_Storage_Long(storage_index + 3)
      set sect_loc := Sys_Get_Event_Storage_Long(storage_index + 4)

      set time_remaining := time_remaining - 1
      call Sys_Set_Event_Storage_Long(storage_index + 0, time_remaining)

      case event_id
        EVENT_ID_STAR_DESTROYED:
          if (time_remaining = 0) then
            call Execute_Event_Star_Destroyed_End(obj_id)
          else
            call Execute_Event_Star_Destroyed_In_Progress(obj_id, time_remaining)
          endif
        EVENT_ID_NEBULAE_CREATED:
          if (time_remaining = 0) then
            call Execute_Event_Nebulae_Created_End(obj_id)
          else
            call Execute_Event_Nebulae_Created_In_Progress(obj_id, time_remaining)
          endif
        EVENT_ID_BLACK_HOLE_CREATED:
          if (time_remaining = 0) then
            call Execute_Event_Black_Hole_Created_End(obj_id)
          else
            call Execute_Event_Black_Hole_Created_In_Progress(obj_id, time_remaining)
          endif
      endcase

    endfor
  endif

  // Delete events that have finished
  if (num_timed_events > 0) then
    set index := 0
    loop
      set index := index + 1
      set storage_index := BASE_EVENT_RECORD_LENGTH + (index * TIMED_EVENT_RECORD_LENGTH)
      set time_remaining := Sys_Get_Event_Storage_Long(storage_index + 0)
      if (time_remaining = 0) then
        // Delete this entry
        if (index < num_timed_events) then
          for sub_index := index to num_timed_events - 1 do
            set sub_storage_index1 := BASE_EVENT_RECORD_LENGTH + (sub_index * TIMED_EVENT_RECORD_LENGTH)
            set sub_storage_index2 := BASE_EVENT_RECORD_LENGTH + ((sub_index + 1) * TIMED_EVENT_RECORD_LENGTH)
            call Sys_Set_Event_Storage_Long(sub_storage_index1 + 0, Sys_Get_Event_Storage_Long(sub_storage_index2 + 0))
            call Sys_Set_Event_Storage_Long(sub_storage_index1 + 1, Sys_Get_Event_Storage_Long(sub_storage_index2 + 1))
            call Sys_Set_Event_Storage_Long(sub_storage_index1 + 2, Sys_Get_Event_Storage_Long(sub_storage_index2 + 2))
            call Sys_Set_Event_Storage_Long(sub_storage_index1 + 3, Sys_Get_Event_Storage_Long(sub_storage_index2 + 3))
            call Sys_Set_Event_Storage_Long(sub_storage_index1 + 4, Sys_Get_Event_Storage_Long(sub_storage_index2 + 4))
          endfor
        endif
        set num_timed_events := num_timed_events - 1
      endif

      exitwhen (index >= num_timed_events) or (num_timed_events = 0)
    endloop
  endif
  call Sys_Set_Event_Storage_Long(1, num_timed_events)

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Star_Destroyed_Begin
//------------------------------------------------------------------------
function Execute_Event_Star_Destroyed_Begin returns boolean
params
  star_id:                   long
vars
  sys_loc:                   long
  sect_loc:                  long
  star_name:                 string
  time_remaining:            long
  log_type:                  long
  num_timed_events:          long
  storage_index:             long
begin

  if (star_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(star_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(star_id)
    set star_name := Sys_Get_Space_Object_Name(star_id)

    set time_remaining := Sys_Get_Random_Long(7, 20)
 
    set num_timed_events := Sys_Get_Event_Storage_Long(1)
    set num_timed_events := num_timed_events + 1
    set storage_index := BASE_EVENT_RECORD_LENGTH + (num_timed_events * TIMED_EVENT_RECORD_LENGTH)
    call Sys_Set_Event_Storage_Long(1, num_timed_events)
    call Sys_Set_Event_Storage_Long(storage_index + 0, time_remaining)
    call Sys_Set_Event_Storage_Long(storage_index + 1, EVENT_ID_STAR_DESTROYED)
    call Sys_Set_Event_Storage_Long(storage_index + 2, star_id)
    call Sys_Set_Event_Storage_Long(storage_index + 3, sys_loc)
    call Sys_Set_Event_Storage_Long(storage_index + 4, sect_loc)

    call Execute_Event_Star_Destroyed_In_Progress(star_id, time_remaining)

  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Star_Destroyed_In_Progress
//------------------------------------------------------------------------
function Execute_Event_Star_Destroyed_In_Progress returns boolean
params
  star_id:                   long
  time_remaining:            long
vars
  sys_loc:                   long
  sect_loc:                  long
  star_name:                 string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  if (star_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(star_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(star_id)
    set star_name := Sys_Get_Space_Object_Name(star_id)

    // Log Message to owner
    set log_type := LOG_TYPE_EVENT
    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 22 Title")
    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 22 Text")
    set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 22 Small Picture Filename")
    set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 22 Large Picture Filename")

    set message_text := Sys_Replace_String(message_text, "[%StarName%]", star_name, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%TimeRemaining%]", Sys_Convert_Long_To_Date_String(time_remaining), TRUE, TRUE)

    call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Star_Destroyed_End
//------------------------------------------------------------------------
function Execute_Event_Star_Destroyed_End returns boolean
params
  star_id:                   long
vars
  star_destroyed:            boolean := FALSE
  sys_loc:                   long
  sect_loc:                  long
  star_name:                 string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Destroy the selected star
  if (star_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(star_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(star_id)
    set star_name := Sys_Get_Space_Object_Name(star_id)

    set star_destroyed := Sys_Destroy_Star(star_id)

    if (star_destroyed) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_STAR_DESTROYED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 32 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 32 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 32 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 32 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%StarName%]", star_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return star_destroyed
end

//------------------------------------------------------------------------
// Execute_Event_Nebulae_Created_Begin
//------------------------------------------------------------------------
function Execute_Event_Nebulae_Created_Begin returns boolean
params
  star_id:                   long
vars
  sys_loc:                   long
  sect_loc:                  long
  star_name:                 string
  time_remaining:            long
  log_type:                  long
  num_timed_events:          long
  storage_index:             long
begin

  if (star_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(star_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(star_id)
    set star_name := Sys_Get_Space_Object_Name(star_id)

    set time_remaining := Sys_Get_Random_Long(7, 20)
 
    set num_timed_events := Sys_Get_Event_Storage_Long(1)
    set num_timed_events := num_timed_events + 1
    set storage_index := BASE_EVENT_RECORD_LENGTH + (num_timed_events * TIMED_EVENT_RECORD_LENGTH)
    call Sys_Set_Event_Storage_Long(1, num_timed_events)
    call Sys_Set_Event_Storage_Long(storage_index + 0, time_remaining)
    call Sys_Set_Event_Storage_Long(storage_index + 1, EVENT_ID_NEBULAE_CREATED)
    call Sys_Set_Event_Storage_Long(storage_index + 2, star_id)
    call Sys_Set_Event_Storage_Long(storage_index + 3, sys_loc)
    call Sys_Set_Event_Storage_Long(storage_index + 4, sect_loc)

    call Execute_Event_Nebulae_Created_In_Progress(star_id, time_remaining)

  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Nebulae_Created_In_Progress
//------------------------------------------------------------------------
function Execute_Event_Nebulae_Created_In_Progress returns boolean
params
  star_id:                   long
  time_remaining:            long
vars
  sys_loc:                   long
  sect_loc:                  long
  star_name:                 string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  if (star_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(star_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(star_id)
    set star_name := Sys_Get_Space_Object_Name(star_id)

    // Log Message to owner
    set log_type := LOG_TYPE_EVENT
    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 27 Title")
    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 27 Text")
    set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 27 Small Picture Filename")
    set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 27 Large Picture Filename")

    set message_text := Sys_Replace_String(message_text, "[%StarName%]", star_name, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%TimeRemaining%]", Sys_Convert_Long_To_Date_String(time_remaining), TRUE, TRUE)

    call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Nebulae_Created_End
//------------------------------------------------------------------------
function Execute_Event_Nebulae_Created_End returns boolean
params
  star_id:                   long
vars
  nebulae_created:           boolean := FALSE
  sys_loc:                   long
  sect_loc:                  long
  star_name:                 string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  if (star_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(star_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(star_id)
    set star_name := Sys_Get_Space_Object_Name(star_id)

    set nebulae_created := Sys_Create_Nebulae(star_id)

    if (nebulae_created) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_NEBULAE_CREATED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 33 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 33 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 33 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 33 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%StarName%]", star_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return nebulae_created
end

//------------------------------------------------------------------------
// Execute_Event_Black_Hole_Created_Begin
//------------------------------------------------------------------------
function Execute_Event_Black_Hole_Created_Begin returns boolean
params
  star_id:                   long
vars
  sys_loc:                   long
  sect_loc:                  long
  star_name:                 string
  time_remaining:            long
  log_type:                  long
  num_timed_events:          long
  storage_index:             long
begin

  if (star_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(star_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(star_id)
    set star_name := Sys_Get_Space_Object_Name(star_id)

    set time_remaining := Sys_Get_Random_Long(7, 20)
 
    set num_timed_events := Sys_Get_Event_Storage_Long(1)
    set num_timed_events := num_timed_events + 1
    set storage_index := BASE_EVENT_RECORD_LENGTH + (num_timed_events * TIMED_EVENT_RECORD_LENGTH)
    call Sys_Set_Event_Storage_Long(1, num_timed_events)
    call Sys_Set_Event_Storage_Long(storage_index + 0, time_remaining)
    call Sys_Set_Event_Storage_Long(storage_index + 1, EVENT_ID_STAR_DESTROYED)
    call Sys_Set_Event_Storage_Long(storage_index + 2, star_id)
    call Sys_Set_Event_Storage_Long(storage_index + 3, sys_loc)
    call Sys_Set_Event_Storage_Long(storage_index + 4, sect_loc)
    call Execute_Event_Star_Destroyed_In_Progress(star_id, time_remaining)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Black_Hole_Created_In_Progress
//------------------------------------------------------------------------
function Execute_Event_Black_Hole_Created_In_Progress returns boolean
params
  star_id:                   long
  time_remaining:            long
vars
  sys_loc:                   long
  sect_loc:                  long
  star_name:                 string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Send out a message each turn to remind players of impending black hole formation
  if (star_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(star_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(star_id)
    set star_name := Sys_Get_Space_Object_Name(star_id)

    // Log Message to owner
    set log_type := LOG_TYPE_EVENT
    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 29 Title")
    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 29 Text")
    set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 29 Small Picture Filename")
    set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 29 Large Picture Filename")

    set message_text := Sys_Replace_String(message_text, "[%StarName%]", star_name, TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)
    set message_text := Sys_Replace_String(message_text, "[%TimeRemaining%]", Sys_Convert_Long_To_Date_String(time_remaining), TRUE, TRUE)

    call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Black_Hole_Created_End
//------------------------------------------------------------------------
function Execute_Event_Black_Hole_Created_End returns boolean
params
  star_id:                   long
vars
  black_hole_created:        boolean := FALSE
  sys_loc:                   long
  sect_loc:                  long
  star_name:                 string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Create a random black hole
  if (star_id > 0) then
    set sys_loc := Sys_Get_Space_Object_System_Location(star_id)
    set sect_loc := Sys_Get_Space_Object_Sector_Location(star_id)
    set star_name := Sys_Get_Space_Object_Name(star_id)

    set black_hole_created := Sys_Create_Black_Hole(star_id)

    if (black_hole_created) then
      // Log Message to owner
      set log_type := LOG_TYPE_STELLAR_BLACK_HOLE_CREATED
      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 34 Title")
      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 34 Text")
      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 34 Small Picture Filename")
      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 34 Large Picture Filename")

      set message_text := Sys_Replace_String(message_text, "[%StarName%]", star_name, TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sys_loc), TRUE, TRUE)
      set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sect_loc), TRUE, TRUE)

      call Give_Message_To_Players(MESSAGE_TO_SYSTEM, 0, sys_loc, sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
    endif
  endif

  return black_hole_created
end

//------------------------------------------------------------------------
// Execute_Dimensional_Rift_Damage
//------------------------------------------------------------------------
function Execute_Dimensional_Rift_Damage returns boolean
params
vars
  plr_count:                 long
  plr_index:                 long
  has_rift_tech:             boolean := FALSE
  colony_count:              long
  colony_index:              long
  colony_id:                 long
  colony_sys_loc:            long
  colony_sect_loc:           long
  lst_colonies:              longlist
  lst_facility_id:           longlist
  lst_facility_level:        longlist
  facility_count:            long
  facility_index:            long
  facility_id:               long
  facility_name:             string
  facility_level:            long
  has_facility:              boolean
  rift_index:                long
  rift_level:                long
  lst_rift_sys_count:        long
  lst_rift_sys_loc:          longlist
  lst_rift_sect_loc:         longlist
  lst_rift_sys_level:        longlist
  rift_chance:               long
  rift_damage:               long
  rift_sys_loc:              long
  rift_sect_loc:             long
  rift_distance:             long
  random_chance:             long
  sobj_list:                 longlist
  sobj_count:                long
  sobj_index:                long
  sobj_id:                   long
  sobj_owner:                long
  sobj_type:                 long
  sobj_name:                 string
  sobj_sys_loc:              long
  sobj_sect_loc:             long
  sobj_structure:            long
  sobj_armor:                long
  sobj_destroyed:            boolean := FALSE
  dmg_amount:                long
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get number of players
  set plr_count := Sys_Get_Number_Of_Players()

  // Debug Output
  call Sys_Debug_Print("Events", "")
  call Sys_Debug_Print("Events", "Dimensional Rift Damage")
  call Sys_Debug_Print("Events", "-----------------------")

  // Check for any Dimensional Rift Facilities on a player's colonies
  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      // Clear previous lists and counts
      call lst_colonies.clear()
      call lst_facility_id.clear()
      call lst_facility_level.clear()
      call lst_rift_sys_loc.clear()
      call lst_rift_sect_loc.clear()
      call lst_rift_sys_level.clear()
      set lst_rift_sys_count := 0
      set colony_index := 0
      // Is this an Interdimensional Player that has access to the technology to build a Dimensional Rift Projector?
      set has_rift_tech := Sys_Get_Empire_Research_Tech_Level(plr_index, Sys_Get_Tech_ID("Interdimensional Technology")) >= 8
      // If the player has access to Interdimensional Technology at the level or above to build the Dimensional Rift Projector then check their colonies for the facility
      if (has_rift_tech) then
        // Debug output
        call Sys_Debug_Print("Events", "  - " + Sys_Empire_Get_Empire_Name(plr_index) + " has the technology!")
        // Get a list of the player's colonies
        set colony_count := Sys_Get_List_Of_Players_Colonies(plr_index, lst_colonies)
        // Check each colony for the presence of a Dimensional Rift Projector
        if (colony_count > 0) then
          loop
            set colony_index := colony_index + 1
            set colony_id := lst_colonies.get(colony_index)
            set colony_sys_loc := Sys_Get_Space_Object_System_Location(colony_id)
            set colony_sect_loc := Sys_Get_Space_Object_Sector_Location(colony_id)
            set has_facility := FALSE
            // Don't keep checking the system if we found a facility
            if lst_rift_sys_loc.indexof(colony_sys_loc) > 0 then
              // Skip check if we already found a facility in this colony's system
            else
              // Get a list of the colony's facilities
              call Sys_Get_Space_Object_Cargo_List_Of_Facilities(colony_id, lst_facility_id, lst_facility_level)
              set facility_count := lst_facility_id.count()
              set facility_index := 0
              // Examine the colony's facilities
              if (facility_count > 0) then
                loop
                  set facility_index := facility_index + 1
                  set facility_id := lst_facility_id.get(facility_index)
                  set facility_name := Sys_Get_Facility_Name(facility_id)
                  set facility_level := lst_facility_level.get(facility_index)
                  // Check for the facility
                  if facility_name = "Dimensional Rift Projector" then
                    set has_facility := TRUE
                    set rift_level := facility_level
                    // Add this system to the list of rift systems
                    if (lst_rift_sys_loc.indexof(colony_sys_loc) < 1) then
                      call lst_rift_sys_loc.add(colony_sys_loc)
                      call lst_rift_sect_loc.add(colony_sect_loc)
                      call lst_rift_sys_level.add(rift_level)
                      // Debug Output
                      call Sys_Debug_Print("Events", "    - " + Sys_Empire_Get_Empire_Name(plr_index) + " has a Dimensional Rift Facility in the " + Sys_Get_Solar_System_Name(colony_sys_loc) + " system level " + Sys_Convert_Long_To_String(rift_level))
                    endif
                  endif
                  // Stop checking if we have found a facility
                  exitwhen (facility_index >= facility_count) or (has_facility)
                endloop
              endif
            endif
            // Pending
            exitwhen (colony_index >= colony_count)
          endloop
        endif
      else
        // Player doesn't have Interdimensional technology
        // Debug output
        call Sys_Debug_Print("Events", "  - " + Sys_Empire_Get_Empire_Name(plr_index) + " doesn't have the technology!")
      endif

      // Execute rift damage to enemy ships in each system with a Dimensional Rift Projector
      set lst_rift_sys_count := lst_rift_sys_loc.count()
      // Check for enemy ships in the system
      if lst_rift_sys_count > 0 then
        for rift_index := 1 to lst_rift_sys_count do
          set rift_sys_loc := lst_rift_sys_loc.get(rift_index)
          set rift_sect_loc := lst_rift_sect_loc.get(rift_index)
          set rift_level := lst_rift_sys_level.get(rift_index)
          // Debug output
          call Sys_Debug_Print("Events", "    - Apply damage in the " + Sys_Get_Solar_System_Name(rift_sys_loc) + " system!")
          // Examine all the visible objects the Dimensional Rift Projector owner can see
          call Sys_Get_All_Visible_Space_Objects_In_System(plr_index, rift_sys_loc, sobj_list)
          set sobj_count := sobj_list.count()
          // Check each visible object
          if (sobj_count > 0) then
            for sobj_index := 1 to sobj_count do
              // Get the space object's details
              set sobj_id := sobj_list.get(sobj_index)
              set sobj_owner := Sys_Get_Space_Object_Owner(sobj_id)
              set sobj_type := Sys_Get_Space_Object_Type(sobj_id)
              set sobj_name := Sys_Get_Space_Object_Name(sobj_id)
              set sobj_sys_loc := rift_sys_loc
              set sobj_sect_loc := Sys_Get_Space_Object_Sector_Location(sobj_id)
              set rift_distance := Sys_Get_Hex_Distance_Between_Sectors(sobj_owner, sobj_sys_loc, sobj_sect_loc, rift_sys_loc, rift_sect_loc)

              // Only strike ships/bases and unit groups of enemies (no treaty or war status)
              if (sobj_type = SPACE_OBJECT_TYPE_SHIP) or (sobj_type = SPACE_OBJECT_TYPE_UNITGROUP) then
                if Sys_Empire_Politics_Is_Player_Enemy(plr_index, sobj_owner) and (plr_index <> sobj_owner) then
                  // Debug output
                  call Sys_Debug_Print("Events", "      - Possible Target = " + Sys_Get_Space_Object_Name(sobj_id) + " (" + Sys_Empire_Get_Empire_Name(sobj_owner) + ")")
                  // Special damage factors for AI Dimensional Rift Projector
                  if (rift_level > 0) then
                    if Sys_Are_We_Computer_Player(plr_index) then
                      // Damage AI player vs AI player
                      if Sys_Are_We_Computer_Player(sobj_owner) then
                        set rift_chance := 10 * rift_level
                        set rift_damage := 10 - Sys_Divide_Long(rift_distance, rift_level * 3)
                      else
                        // Damage AI player vs Human player
                        set rift_chance := 15 * rift_level
                        set rift_damage := 15 - Sys_Divide_Long(rift_distance, rift_level * 3)
                      endif
                    else
                      // Human player vs any player
                      set rift_chance := 10 * rift_level
                      set rift_damage := 10 - Sys_Divide_Long(rift_distance, rift_level * 3)
                    endif
                  endif
                  // Pending
                  set rift_damage := Sys_Max_Long(2, rift_damage)
                  // Out of 100
                  set random_chance := Sys_Get_Random_Long(1, 100)
                  // Debug output
                  call Sys_Debug_Print("Events", "      - Rift Chance = " + Sys_Convert_Long_To_String(rift_chance) + "%; Roll = " Sys_Convert_Long_To_String(random_chance) + " and Rift Damage = " + Sys_Convert_Long_To_String(rift_damage) + "x")

                  // Get the object's structure (tonnage structure - armor)
                  set sobj_structure := Sys_Get_Space_Object_Total_Tonnage_Structure(sobj_id) - Sys_Get_Space_Object_Current_Armor_Structure(sobj_id)
                  // Determine the damage amount if the Dimensional Rift Projector did damage to the space object...
                  if (rift_chance >= random_chance) then
                    set dmg_amount := Sys_Get_Random_Long(rift_level * rift_damage * 4, rift_level * rift_damage * 8)
                    // Apply the damage to the space object
                    call Sys_Space_Object_Take_Damage(sobj_id, "Skips Almost All Shields And Armor", dmg_amount)
                    // Debug output
                    call Sys_Debug_Print("Events", "        - Hit Target! Rift damage = " + Sys_Convert_Long_To_String(dmg_amount) + " kT")
                    // Possible reasons
                    case Sys_Get_Random_Long(1, 4)
                      1:
                        set event_cause := "A mysterious dimensional rift"
                      2:
                        set event_cause := "A dimensional rift possibly directed by the " + Sys_Empire_Get_Empire_Name(plr_index)
                      3:
                        set event_cause := "A freak spatial anomaly"
                      4:
                        set event_cause := "A type of unknown anomaly"
                    endcase

                    // Was the space object destroyed?
                    set sobj_destroyed := (dmg_amount >= sobj_structure)

                    // Log Message to owner
                    set log_type := LOG_TYPE_SHIP_DAMAGED

                    if (sobj_destroyed) then
                      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 36 Title")
                      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 36 Text")
                      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 36 Small Picture Filename")
                      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 36 Large Picture Filename")
                    else
                      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 35 Title")
                      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 35 Text")
                      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 35 Small Picture Filename")
                      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 35 Large Picture Filename")
                    endif

                    set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", sobj_name, TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%DamageAmount%]", Sys_Convert_Long_To_String(dmg_amount), TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sobj_sys_loc), TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sobj_sect_loc), TRUE, TRUE)
                    // Create the log message
                    call Give_Message_To_Players(MESSAGE_TO_OWNER, sobj_owner, sobj_sys_loc, sobj_sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
                    // Debug output
                    call Sys_Debug_Print("Events", "      - " + message_text)

                    // Log message to Dimensional Rift Projector owner
                    if (sobj_destroyed) then
                      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 38 Title")
                      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 38 Text")
                      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 38 Small Picture Filename")
                      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 38 Large Picture Filename")
                    else
                      set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 37 Title")
                      set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 37 Text")
                      set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 37 Small Picture Filename")
                      set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 37 Large Picture Filename")
                    endif

                    set message_text := Sys_Replace_String(message_text, "[%VehicleOwner%]", Sys_Empire_Get_Empire_Name(sobj_owner), TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", sobj_name, TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%DamageAmount%]", Sys_Convert_Long_To_String(dmg_amount), TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sobj_sys_loc), TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sobj_sect_loc), TRUE, TRUE)
                    // Create the log message
                    call Give_Message_To_Players(MESSAGE_TO_OWNER, plr_index, sobj_sys_loc, sobj_sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
                    // Debug output
                    call Sys_Debug_Print("Events", "      - " + message_text)
                  else
                    // Debug output
                    call Sys_Debug_Print("Events", "        - Did not hit target")
                  endif
                endif
              endif
            endfor
          endif
        endfor
      endif
      // End damage application phase
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Subverter_Damage
//------------------------------------------------------------------------
function Execute_Subverter_Damage returns boolean
params
vars
  plr_count:                 long
  plr_index:                 long
  has_subverter_tech:        boolean := FALSE
  colony_count:              long
  colony_index:              long
  colony_id:                 long
  colony_sys_loc:            long
  colony_sect_loc:           long
  lst_colonies:              longlist
  lst_facility_id:           longlist
  lst_facility_level:        longlist
  facility_count:            long
  facility_index:            long
  facility_id:               long
  facility_name:             string
  facility_level:            long
  has_facility:              boolean
  subverter_index:           long
  subverter_sys_loc:         long
  subverter_sect_loc:        long
  subverter_level:           long
  subverter_sys_count:       long
  lst_subverter_sys_loc:     longlist
  lst_subverter_sect_loc:    longlist
  lst_subverter_sys_level:   longlist
  subverter_chance:          long
  random_chance:             long
  sobj_list:                 longlist
  sobj_count:                long
  sobj_index:                long
  sobj_id:                   long
  sobj_owner:                long
  sobj_type:                 long
  sobj_name:                 string
  sobj_sys_loc:              long
  sobj_sect_loc:             long
  sobj_dist:                 long
  sobj_capturable:           boolean := FALSE
  sobj_captured:             boolean := FALSE
  comp_count:                long
  comp_index:                long
  comp_pos:                  long
  comp_id:                   long
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get number of players
  set plr_count := Sys_Get_Number_Of_Players()

  // Debug Output
  call Sys_Debug_Print("Events", "")
  call Sys_Debug_Print("Events", "Allegiance Subverter Amplifier Damage:")
  call Sys_Debug_Print("Events", "--------------------------------------")

  // Check for any Allegiance Subverter Amplifier facilities on a player's colonies
  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      // Clear previous lists and counts
      call lst_colonies.clear()
      call lst_facility_id.clear()
      call lst_facility_level.clear()
      call lst_subverter_sys_loc.clear()
      call lst_subverter_sect_loc.clear()
      call lst_subverter_sys_level.clear()
      set subverter_sys_count := 0
      set colony_index := 0
      // Is this an Psychic Player that has access to the technology to build a Allegiance Subverter Amplifier?
      set has_subverter_tech := Sys_Get_Empire_Research_Tech_Level(plr_index, Sys_Get_Tech_ID("Psychic Technology")) >= 5
      // If the player has access to Psychic Technology at the level or above to build the Allegiance Subverter Amplifier then check their colonies for the facility
      if (has_subverter_tech) then
        // Debug output
        call Sys_Debug_Print("Events", "  - " + Sys_Empire_Get_Empire_Name(plr_index) + " has the technology!")
        // Get a list of the player's colonies
        set colony_count := Sys_Get_List_Of_Players_Colonies(plr_index, lst_colonies)
        // Check each colony for the presence of an Allegiance Subverter Amplifier
        if (colony_count > 0) then
          loop
            set colony_index := colony_index + 1
            set colony_id := lst_colonies.get(colony_index)
            set colony_sys_loc := Sys_Get_Space_Object_System_Location(colony_id)
            set colony_sect_loc := Sys_Get_Space_Object_Sector_Location(colony_id)
            set has_facility := FALSE
            // Don't keep checking the system if we found a facility
            if lst_subverter_sys_loc.indexof(colony_sys_loc) > 0 then
              // Skip check if we already found a facility in this colony's system
            else
              // Get a list of the colony's facilities
              call Sys_Get_Space_Object_Cargo_List_Of_Facilities(colony_id, lst_facility_id, lst_facility_level)
              set facility_count := lst_facility_id.count()
              set facility_index := 0
              // Examine the colony's facilities
              if (facility_count > 0) then
                loop
                  set facility_index := facility_index + 1
                  set facility_id := lst_facility_id.get(facility_index)
                  set facility_name := Sys_Get_Facility_Name(facility_id)
                  set facility_level := lst_facility_level.get(facility_index)
                  // Check for the facility
                  if facility_name = "Allegiance Subverter Amplifier" then
                    set has_facility := TRUE
                    set subverter_level := facility_level
                    // Add this system to the list of Allegiance Subverter Amplifier systems
                    if lst_subverter_sys_loc.indexof(colony_sys_loc) < 1 then
                      call lst_subverter_sys_loc.add(colony_sys_loc)
                      call lst_subverter_sect_loc.add(colony_sect_loc)
                      call lst_subverter_sys_level.add(subverter_level)
                      // Debug Output
                      call Sys_Debug_Print("Events", "    - " + Sys_Empire_Get_Empire_Name(plr_index) + " has an Allegiance Subverter Amplifier in the " + Sys_Get_Solar_System_Name(colony_sys_loc) + " system level " + Sys_Convert_Long_To_String(subverter_level))
                    endif
                  endif
                  // Stop checking if we have found a facility
                  exitwhen (facility_index >= facility_count) or (has_facility)
                endloop
              endif
            endif
            // Exit when there are no more colonies to check
            exitwhen (colony_index >= colony_count)
          endloop
        endif
      else
        // Player doesn't have Psychic Technology
        // Debug output
        call Sys_Debug_Print("Events", "  - " + Sys_Empire_Get_Empire_Name(plr_index) + " doesn't have the technology!")
      endif

      // Execute subverter damage to enemy ships in each system with a Allegiance Subverter Amplifier
      set subverter_sys_count := lst_subverter_sys_loc.count()
      // Check for enemy ships in the system
      if (subverter_sys_count > 0) then
        for subverter_index := 1 to subverter_sys_count do
          set subverter_sys_loc := lst_subverter_sys_loc.get(subverter_index)
          set subverter_sect_loc := lst_subverter_sect_loc.get(subverter_index)
          set subverter_level := lst_subverter_sys_level.get(subverter_index)
          // Debug output
          call Sys_Debug_Print("Events", "    - Apply damage in the " + Sys_Get_Solar_System_Name(subverter_sys_loc) + " system!")
          // Examine all the visible objects the Allegiance Subverter Amplifier owner can see
          call Sys_Get_All_Visible_Space_Objects_In_System(plr_index, subverter_sys_loc, sobj_list)
          set sobj_count := sobj_list.count()
          // Check each visible object
          if (sobj_count > 0) then
            for sobj_index := 1 to sobj_count do
              // Get the space object's details
              set sobj_id := sobj_list.get(sobj_index)
              set sobj_owner := Sys_Get_Space_Object_Owner(sobj_id)
              set sobj_type := Sys_Get_Space_Object_Type(sobj_id)
              set sobj_name := Sys_Get_Space_Object_Name(sobj_id)
              set sobj_sys_loc := subverter_sys_loc
              set sobj_sect_loc := Sys_Get_Space_Object_Sector_Location(sobj_id)
              set sobj_dist := Sys_Get_Hex_Distance_Between_Sectors(sobj_owner, sobj_sys_loc, sobj_sect_loc, subverter_sys_loc, subverter_sect_loc)
              set sobj_capturable := FALSE
              set sobj_captured := FALSE

              // Only ships with crews can be capturable...
              if (sobj_type = SPACE_OBJECT_TYPE_SHIP) then
                // Get the number of components on our ship
                set comp_count := Sys_Get_Space_Object_Comp_Count(sobj_id)
                set comp_index := 0
                set comp_pos := 0
                set comp_id := Sys_Get_Component_With_Name(sobj_owner, "Crew Quarters")
                // Do a quick check for the presence of crew quarters
                if (comp_count > 0) then
                  loop
                    set comp_index := comp_index + 1
                    // If the ship has crew quarters, it's considered capturable
                    if (Sys_Get_Space_Object_Comp_Info_Comp_ID(sobj_id, comp_index) = comp_id) then
                      set comp_pos := comp_index
                      set sobj_capturable := TRUE
                    endif
                    exitwhen (comp_pos > 0) or (comp_index >= comp_count)
                  endloop
                endif
              endif

              // Only strike ships/bases of enemies (no treaty or war status) that are capturable
              if (sobj_capturable) then
                if Sys_Empire_Politics_Is_Player_Enemy(plr_index, sobj_owner) and (plr_index <> sobj_owner) then
                  // Debug output
                  call Sys_Debug_Print("Events", "      - Possible Target = " + Sys_Get_Space_Object_Name(sobj_id) + " (" + Sys_Empire_Get_Empire_Name(sobj_owner) + ")")
                  // Special damage factors for AI operated Allegiance Subverter Amplifier
                  if Sys_Are_We_Computer_Player(plr_index) then
                    // Chance AI player vs AI player
                    if Sys_Are_We_Computer_Player(sobj_owner) then
                      set subverter_chance := 2 * subverter_level
                    else
                      // Chance AI player vs Human player
                      set subverter_chance := 4 * subverter_level
                    endif
                  else
                    // Chance Human player vs AI player
                    if Sys_Are_We_Computer_Player(sobj_owner) then
                      set subverter_chance := 2 * subverter_level
                    else
                      // Chance Human player vs human player
                      set subverter_chance := 4 * subverter_level
                    endif
                  endif
                  // Modify Subverter chance by distance
                  if (sobj_dist > (subverter_level * 5)) then
                    set subverter_chance := Sys_Divide_Long(subverter_chance, 2)
                  endif
                  // Out of 100
                  set random_chance := Sys_Get_Random_Long(1, 100)
                  // Debug output
                  call Sys_Debug_Print("Events", "      - Allegiance Subverter Chance = " + Sys_Convert_Long_To_String(subverter_chance) + "%; Roll = " + Sys_Convert_Long_To_String(random_chance))

                  // Change the ownership of the object to the Allegiance Subverter Owner if the subversion was successful
                  if (random_chance <= subverter_chance) then
                    // Target is converted
                    call Sys_Space_Object_Set_To_New_Owner(sobj_id, plr_index)
                    set sobj_captured := TRUE
                  else
                    set sobj_captured := FALSE
                  endif

                  if (sobj_captured) then
                    // Debug output
                    call Sys_Debug_Print("Events", "        - Target Converted!")
                    // Possible reasons
                    case Sys_Get_Random_Long(1, 2)
                      1:
                        set event_cause := "A remote psychic weapon operated by the " + Sys_Empire_Get_Empire_Name(plr_index)
                      2:
                        set event_cause := "The " + Sys_Empire_Get_Empire_Name(plr_index) + " executed some form of a psychic attack that has"
                    endcase

                    // Log Message to owner
                    set log_type := LOG_TYPE_SHIP_REBEL

                    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 41 Title")
                    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 41 Text")
                    set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 41 Small Picture Filename")
                    set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 41 Large Picture Filename")

                    set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", sobj_name, TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sobj_sys_loc), TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sobj_sect_loc), TRUE, TRUE)
                    // Create the log message
                    call Give_Message_To_Players(MESSAGE_TO_OWNER, sobj_owner, sobj_sys_loc, sobj_sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
                    // Debug output
                    call Sys_Debug_Print("Events", "      - " + message_text)

                    // Log message to Allegiance Subverter Amplifier owner
                    set log_type := LOG_TYPE_SHIP_REBEL

                    set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 42 Title")
                    set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 42 Text")
                    set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 42 Small Picture Filename")
                    set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 42 Large Picture Filename")

                    set message_text := Sys_Replace_String(message_text, "[%VehicleOwner%]", Sys_Empire_Get_Empire_Name(sobj_owner), TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", sobj_name, TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(sobj_sys_loc), TRUE, TRUE)
                    set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(sobj_sect_loc), TRUE, TRUE)
                    // Create the log message
                    call Give_Message_To_Players(MESSAGE_TO_OWNER, plr_index, sobj_sys_loc, sobj_sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
                    // Debug output
                    call Sys_Debug_Print("Events", "      - " + message_text)
                  else
                    // Debug output
                    call Sys_Debug_Print("Events", "        - Did not hit target")
                  endif
                endif
              endif
            endfor
          endif
        endfor
      endif
      // End damage application phase
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Random_Research
//------------------------------------------------------------------------
function Execute_Event_Random_Research returns boolean
params
vars
  plr_count:                 long
  plr_index:                 long
  luck_pct:                  long
  tech_count:                long
  tech_index:                long
  tech_id:                   long
  tech_name:                 string
  research_pts:              long
  research_accum:            real
  research_cost:             real
  research_left:             real
  research_spend:            real
  research_spend_pct:        long
  research_comp_pct:         long
  research_adj:              real
  research_min:              long
  research_max:              long
  chance_roll:               long
  chance_roll_luck:          long
  chance_breakthrough:       long
  mod_breakthrough:          real
  chance_setback:            long
  mod_setback:               real
  research_breakthrough:     boolean
  research_setback:          boolean
  skip_tech_area:            boolean
  msg_amt:                   string
  msg_text:                  string
begin

  // Get number of players
  set plr_count := Sys_Get_Number_Of_Players()

  // Debug Output
  call Sys_Debug_Print("Events", "")
  call Sys_Debug_Print("Events", "Research Events")
  call Sys_Debug_Print("Events", "---------------")

  // For each player, determine if they will have any research breakthroughs or setbacks this turn
  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      set research_pts := Sys_Get_Empire_Current_Points(plr_index, POINT_TYPE_RESEARCH)
      set tech_count := Sys_Get_Tech_Area_Count()
      // Are we lucky?
      if Sys_Does_Empire_Have_Ability(plr_index, "Bad Event Chance") then
        set luck_pct := 75
      else
        set luck_pct := 50
      endif
      // Debug output
      call Sys_Debug_Print("Events", "  - Research events for the " + Sys_Empire_Get_Empire_Name(plr_index))
      call Sys_Debug_Print("Events", "    - Empire Luck = " + Sys_Convert_Long_To_String(luck_pct) + "%")
      // Only allow one setback per turn
      set research_setback := FALSE
      // See which tech areas we are researching
      for tech_index := 1 to tech_count do
        set tech_id := Sys_Get_Tech_By_Index(tech_index)
        set tech_name := Sys_Get_Tech_Area_Name(tech_id)
        // Reset research values
        set research_spend_pct := Sys_Get_Empire_Research_Tech_Area_Spending_Pct(plr_index, tech_id)
        set research_accum := 0.0
        set research_cost := 0.0
        set research_spend := 0.0
        set research_left := 0.0
        set research_adj := 0.0
        // Multiple research breakthroughs are possible in a turn
        set research_breakthrough := FALSE
        // If we are actively research a tech area, get the cost and our accumulated and remaining points in the project
        if (research_spend_pct > 0) then
          set research_accum := Sys_Get_Empire_Research_Tech_Area_Accumulated_Points(plr_index, tech_id)
          set research_cost := Sys_Get_Empire_Research_Tech_Area_Cost_For_Next_Level(plr_index, tech_id)
          set research_spend := research_pts * research_spend_pct / 100
          set research_left := research_cost - research_accum - research_spend
          // Debug Output
          call Sys_Debug_Print("Events", "      - Tech Area = " + tech_name)
          call Sys_Debug_Print("Events", "        - Research cost = " + Sys_Convert_Real_To_String(research_cost))
          call Sys_Debug_Print("Events", "        - Research accumulated = " + Sys_Convert_Real_To_String(research_accum))
          call Sys_Debug_Print("Events", "        - Research spend = " + Sys_Convert_Real_To_String(research_spend))
          call Sys_Debug_Print("Events", "        - Research left = " + Sys_Convert_Real_To_String(research_left))
          // Determine the completion percentage of the tech area
          if (research_cost > 0) then
            set research_comp_pct := Sys_Trunc(100 * research_accum / research_cost)
            call Sys_Debug_Print("Events", "        - Research completion percent = " + Sys_Convert_Long_To_String(research_comp_pct) + "%")
          endif
          // Skip tech areas that are being completed this turn
          if (research_left < research_spend) or (research_comp_pct < 10) or (research_comp_pct > 90) then
            set skip_tech_area := TRUE
          else
            set skip_tech_area := FALSE
          endif
          // Determine the breakthrough/setback chances and modifier amounts based on the completion percentage
          if (research_comp_pct <= 25) then
            set chance_breakthrough := 25
            set chance_setback := 100
            set mod_breakthrough := 0.8
            set mod_setback := 0.9
          endif
          if (research_comp_pct > 25) and (research_comp_pct <= 50) then
            set chance_breakthrough := 50
            set chance_setback := 75
            set mod_breakthrough := 0.833
            set mod_setback := 0.867
          endif
          if (research_comp_pct > 50) and (research_comp_pct <= 75) then
            set chance_breakthrough := 75
            set chance_setback := 50
            set mod_breakthrough := 0.867
            set mod_setback := 0.833
          endif
          if (research_comp_pct > 75) then
            set chance_breakthrough := 100
            set chance_setback := 25
            set mod_breakthrough := 0.9
            set mod_setback := 0.8
          endif
          // Determine if we have a research breakthrough or setback
          if (not skip_tech_area) then
            set chance_roll := Sys_Get_Random_Long(1, 1000)
            set chance_roll_luck := Sys_Get_Random_Long(1, 100)
            // Debug output
            call Sys_Debug_Print("Events", "        - Chance breakthrough = " + Sys_Convert_Long_To_String(chance_breakthrough))
            call Sys_Debug_Print("Events", "        - Rolls = " + Sys_Convert_Long_To_String(chance_roll) + ";" + Sys_Convert_Long_To_String(chance_roll_luck))
            // Did we make a research breakthrough?
            if (chance_breakthrough >= chance_roll) and (luck_pct >= chance_roll_luck) then
              set research_adj := research_left ^ mod_breakthrough
              set research_breakthrough := TRUE
              set msg_amt := Sys_Convert_Real_To_String(research_adj)
              set msg_text := "Sire, we made a breakthrough in the tech area " + tech_name + " and made more progress than expected in the last turn."
              // Create log message
              call Sys_Add_Empire_Log_Entry(plr_index, 0, 0, "Research Breakthrough!", msg_text, "Event_NewTechDiscovered.jpg", "LargePortrait_Event_NewTechDiscovered.jpg", LOG_TYPE_EVENT, LOG_CATEGORY_TYPE_EMPIRE_NEWS, LOG_SUB_CATEGORY_TYPE_EMPIRE_RESEARCH, 1)
              // Debug output
              call Sys_Debug_Print("Events", "    - Breakthrough in " + tech_name + " gained " + msg_amt " research points")
            endif
            // Did we suffer a research setback?
            if (not research_breakthrough) and (not research_setback) then
              set chance_roll := Sys_Get_Random_Long(1, 1000)
              set chance_roll_luck := Sys_Get_Random_Long(1, 100)
              // Debug output
              call Sys_Debug_Print("Events", "        - Chance setback = " + Sys_Convert_Long_To_String(chance_setback))
              call Sys_Debug_Print("Events", "        - Rolls = " + Sys_Convert_Long_To_String(chance_roll) + ";" + Sys_Convert_Long_To_String(chance_roll_luck))
              // Setback?
              if (chance_setback >= chance_roll) and (luck_pct <= chance_roll_luck) then
                set research_adj := -research_accum ^ mod_setback
                set msg_amt := Sys_Convert_Real_To_String(research_adj)
                set msg_text := "Sire, we have suffered a setback in the tech area " + tech_name + " and did not make as much progress as expected over the last turn."
                // Flag research setback
                set research_setback := TRUE
                // Create log message
                call Sys_Add_Empire_Log_Entry(plr_index, 0, 0, "Research Setback!", msg_text, "Event_ResearchDamaged.jpg", "LargePortrait_Event_ResearchDamaged.jpg", LOG_TYPE_EVENT, LOG_CATEGORY_TYPE_EMPIRE_NEWS, LOG_SUB_CATEGORY_TYPE_EMPIRE_RESEARCH, 1)
                // Debug output
                call Sys_Debug_Print("Events", "    - Setback in " + tech_name + " lost " + msg_amt " research points")
              endif
            endif
          endif
        endif
        // Adjust our research points if we have had a setback or breakthrough
        if (research_adj <> 0) then
          call Sys_Change_Empire_Research_Tech_Area_Accomplished_Amount(plr_index, tech_id, research_adj)
        endif
      endfor
    endfor
  endif

  return true
end

//------------------------------------------------------------------------
// Execute_Event_Pollution
//------------------------------------------------------------------------
function Execute_Event_Pollution returns boolean
params
vars
  plr_count:                 long
  plr_index:                 long
  lst_colonies:              longlist
  colony_count:              long
  colony_index:              long
  colony_id:                 long
  colony_name:               string
  colony_sys_loc:            long
  colony_sect_loc:           long
  colony_conditions:         real
  lst_facility_id:           longlist
  lst_facility_level:        longlist
  facility_count:            long
  facility_index:            long
  facility_id:               long
  facility_name:             string
  facility_level:            long
  tech_id:                   long
  tech_level:                long
  environment_reduction:     long
  pollution_pts:             long
  target_conditions:         real
  conditions_change:         real
  early_game:                boolean := TRUE
  msg_text:                  string
  added_text:                string
begin

  // Get number of players
  set plr_count := Sys_Get_Number_Of_Players()

  // Reduce pollution effect for first 25 turns
  if (sys_long_Game_Date - Sys_Get_Game_Start_Date()) > 25 then
    set early_game := FALSE
  endif

  // Debug Output
  call Sys_Debug_Print("Events", "")
  call Sys_Debug_Print("Events", "Pollution Events")
  call Sys_Debug_Print("Events", "----------------")

  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      // Clear previous lists
      call lst_colonies.clear()
      call lst_facility_id.clear()
      call lst_facility_level.clear()
      // Adjust pollution points based on environmental achievements
      set tech_id := Sys_Get_Tech_ID("Environment")
      set tech_level := Sys_Get_Empire_Research_Tech_Level(plr_index, tech_id)
      set environment_reduction := tech_level * 3
      // Debug output
      call Sys_Debug_Print("Events", "  - Colony pollution levels for " + Sys_Empire_Get_Empire_Name(plr_index) + ":")
      call Sys_Debug_Print("Events", "    - Environmental Achievement Reduction = " + Sys_Convert_Long_To_String(environment_reduction))
      // Get a list of the player's colonies
      set colony_count := Sys_Get_List_Of_Players_Colonies(plr_index, lst_colonies)
      // Pending
      if (colony_count > 0) then
        for colony_index := 1 to colony_count do
          set colony_id := lst_colonies.get(colony_index)
          set colony_name := Sys_Get_Space_Object_Name(colony_id)
          set colony_sys_loc := Sys_Get_Space_Object_System_Location(colony_id)
          set colony_sect_loc := Sys_Get_Space_Object_Sector_Location(colony_id)
          set colony_conditions := Sys_Get_Planet_Conditions(colony_id)
          set pollution_pts := 0
          set conditions_change := 0.0
          set msg_text := ""
          set added_text := ""
          // Debug output
          call Sys_Debug_Print("Events", "    - " + colony_name)
          // Get a list of our colony's facilities
          call Sys_Get_Space_Object_Cargo_List_Of_Facilities(colony_id, lst_facility_id, lst_facility_level)
          set facility_count := lst_facility_id.count()
          // Examine the colony's facilities
          if (facility_count > 0) then
            for facility_index := 1 to facility_count do
              set facility_id := lst_facility_id.get(facility_index)
              set facility_name := Sys_Get_Facility_Name(facility_id)
              set facility_level := lst_facility_level.get(facility_index)
              // Assign pollution points based on the facilities present
              case facility_name
                "Space Yard Facility":
                  set pollution_pts := pollution_pts + 5
                "Mineral Miner Facility":
                  set pollution_pts := pollution_pts + 2
                "Organics Farm Facility":
                  set pollution_pts := pollution_pts + 1
                "Radioactives Extraction Facility":
                  set pollution_pts := pollution_pts + 2
                "Monolith Facility":
                  set pollution_pts := pollution_pts + 3
                "Mineral Scanner":
                  set pollution_pts := pollution_pts + 5
                "System Mineral Scanner":
                  set pollution_pts := pollution_pts + 10
                "Hybrid Eco-Farms":
                  set pollution_pts := pollution_pts + 3
                "System Eco-Farms":
                  set pollution_pts := pollution_pts + 5
                "Radioactives Collider":
                  set pollution_pts := pollution_pts + 5
                "System Radioactives Collider":
                  set pollution_pts := pollution_pts + 10
                "Components Factory":
                  set pollution_pts := pollution_pts + 5
                "System Robotoid Factory":
                  set pollution_pts := pollution_pts + 10
                "Ultra-Recycler":
                  set pollution_pts := pollution_pts + 5
                "Resource Converter":
                  set pollution_pts := pollution_pts + 10
                "Climate Control Facility":
                  set pollution_pts := pollution_pts - (10 + (facility_level - 1) * 5)
              endcase
            endfor
          endif

          // Adjust pollution points to the planet's size
          case Sys_Get_Planet_Size(colony_id)
            "Tiny":
              set pollution_pts := Sys_Trunc(pollution_pts * 5.00)
            "Small":
              set pollution_pts := Sys_Trunc(pollution_pts * 2.50)
            "Medium":
              set pollution_pts := Sys_Trunc(pollution_pts * 1.67)
            "Large":
              set pollution_pts := Sys_Trunc(pollution_pts * 1.25)
            "Huge":
              set pollution_pts := Sys_Trunc(pollution_pts * 1.00)
            "Ringworld":
              set pollution_pts := Sys_Trunc(pollution_pts * 0.25)
            "Sphereworld":
              set pollution_pts := Sys_Trunc(pollution_pts * 0.10)
          endcase

          // Domed colony pollution effect
          if Sys_Is_Planet_Domed(colony_id) then
            set pollution_pts := Sys_Trunc(pollution_pts * 2.5)
            // Debug output
            call Sys_Debug_Print("Events", "      - Domed planet modifier applied (x2.5)")
          endif

          // Reduce pollution points based on environmental achievements
          set pollution_pts := Sys_Max_Long(0, pollution_pts - environment_reduction)

          // Reduce pollution effect for first 25 turns
          if (early_game) then
            set pollution_pts := Sys_Divide_Long(pollution_pts, 2)
          else
            // Reduce pollution effect for homeworlds (single homeworld games only)
            if (colony_sys_loc = Sys_Get_Empire_Home_System(plr_index)) and (colony_sect_loc = Sys_Get_Empire_Home_Sector(plr_index)) then
              set pollution_pts := Sys_Divide_Long(pollution_pts, 2)
              call Sys_Debug_Print("Events", "      - Homeworld pollution modifier applied (/2)")
            endif
          endif

          // Debug output
          call Sys_Debug_Print("Events", "      - " + Sys_Convert_Long_To_String(pollution_pts) + " pollution points")

          // Set the conditions target based on the number of pollution points
          if (pollution_pts <= 10) then
            set target_conditions := colony_conditions
          endif
          if (pollution_pts > 10) and (pollution_pts <= 20) then
            set target_conditions := 1.20
            set added_text := " Without further intervention the conditions are trending downwards to mild."
          endif
          if (pollution_pts > 20) and (pollution_pts <= 40) then
            set target_conditions := 0.90
            set added_text := " Without further intervention the conditions are trending downwards to unpleasant."
          endif
          if (pollution_pts > 40) and (pollution_pts <= 60) then
            set target_conditions := 0.60
            set added_text := " Without further intervention the conditions are trending downwards to very unpleasant."
          endif
          if (pollution_pts > 60) and (pollution_pts <= 80) then
            set target_conditions := 0.40
            set added_text := " Without further intervention the conditions are trending downwards to harsh."
          endif
          if (pollution_pts > 80) then
            set target_conditions := 0.20
            set added_text := " Without further intervention the conditions are trending downwards to deadly."
          endif

          // If the target conditions are lower than the current conditions
          if (target_conditions < colony_conditions) then
            set conditions_change := (colony_conditions - target_conditions) / 10
            // Determine if the change to conditions will drop the planet to the next level
            if (colony_conditions >= 1.5) and ((colony_conditions - conditions_change) < 1.5) then
              set msg_text := "Sire, pollution on our planet " + colony_name + " has caused its conditions to drop from optimal to good." + added_text
            endif
            if (colony_conditions >= 1.3) and ((colony_conditions - conditions_change) < 1.3) then
              set msg_text := "Sire, pollution on our planet " + colony_name + " has caused its conditions to drop from good to mild." + added_text
            endif
            if (colony_conditions >= 1.0) and ((colony_conditions - conditions_change) < 1.0) then
              set msg_text := "Sire, pollution on our planet " + colony_name + " has caused its conditions to drop from mild to unpleasant." + added_text
            endif
            if (colony_conditions >= 0.5) and ((colony_conditions - conditions_change) < 0.5) then
              set msg_text := "Sire, pollution on our planet " + colony_name + " has caused its conditions to drop from unpleasant to harsh." + added_text
            endif
            if (colony_conditions >= 0.3) and ((colony_conditions - conditions_change) < 0.3) then
              set msg_text := "Sire, pollution on our planet " + colony_name + " has caused its conditions to drop from harsh to deadly."
            endif

            // Debug output
            call Sys_Debug_Print("Events", "      - Conditions are " + Sys_Convert_Real_To_String(100 * colony_conditions) + " and drop this turn is " + Sys_Convert_Real_To_String(100 * conditions_change))

            // Adjust the colony's conditions due to pollution
            call Sys_Change_Planet_Conditions(colony_id, -conditions_change)
            // Create a log message when the conditions change from one level to another
            if (msg_text <> "") then
              // Create log message
              call Sys_Add_Empire_Log_Entry(plr_index, colony_sys_loc, colony_sect_loc, "Pollution", msg_text, "Event_PlanetConditionWorsened.jpg", "LargePortrait_Event_PlanetConditionWorsened.jpg", LOG_TYPE_PLANET_CONDITION_CHANGE, LOG_CATEGORY_TYPE_EMPIRE_NEWS, LOG_SUB_CATEGORY_TYPE_EMPIRE_MISC, 0)
            endif
          endif
        endfor
      endif
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Event_Plague_Spreading
//------------------------------------------------------------------------
function Execute_Event_Plague_Spreading returns boolean
params
vars
  lst_colonies:              longlist
  colony_count:              long
  colony_index:              long
  colony_id:                 long
  colony_owner:              long
  colony_name:               string
  colony_sys_loc:            long
  colony_sect_loc:           long
  plague_level:              long
  plague_plr:                long
  lst_plague_sys:            longlist
  lst_plague_plr:            longlist
  lst_plague_level:          longlist
  plague_sys_index:          long
  plague_count:              long
  plague_chance:             long
  msg_text:                  string
  added_text:                string
begin

  // Debug Output
  call Sys_Debug_Print("Events", "")
  call Sys_Debug_Print("Events", "Plague Spreading Events")
  call Sys_Debug_Print("Events", "-----------------------")

  // Make a list of all colonized planets
  call Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_PLANET, lst_colonies, TRUE, TRUE, 0)
  set colony_count := lst_colonies.count()

  // Check all colonies for plagues and note the systems with plagues
  if (colony_count > 0) then
    for colony_index := 1 to colony_count do
      set colony_id := lst_colonies.get(colony_index)
      set colony_owner := Sys_Get_Space_Object_Owner(colony_id)
      set colony_name := Sys_Get_Space_Object_Name(colony_id)
      set colony_sys_loc := Sys_Get_Space_Object_System_Location(colony_id)
      set plague_level := Sys_Get_Planet_Plague_Level(colony_id)
      // Plague
      if (plague_level > 0) then
        // Debug text
        call Sys_Debug_Print("Events", "  - " + Sys_Empire_Get_Empire_Name(colony_owner) + ": " + colony_name + " (" + Sys_Get_Solar_System_Name(colony_sys_loc) + " System) has a level " + Sys_Convert_Long_To_String(plague_level) + " plague!")
        // Add the system to a list of systems that have a colony with a plague
        if (lst_plague_sys.count() > 0) then
          // Note the system and player affected
          if (lst_plague_sys.indexof(colony_sys_loc) > 0) then
            // Already on the plagued system List
          else
            // Add the system to the plagued system list with details
            call lst_plague_sys.add(colony_sys_loc)
            call lst_plague_plr.add(colony_owner)
            call lst_plague_level.add(plague_level)
          endif
        else
          // Add the system to the plagued system list with details
          call lst_plague_sys.add(colony_sys_loc)
          call lst_plague_plr.add(colony_owner)
          call lst_plague_level.add(plague_level)
        endif
      endif
    endfor
  endif

  // Run back through the colonies to see if there is an opportunity for the plague to spread...
  set plague_count := lst_plague_sys.count()

  if (plague_count > 0) and (colony_count > 0) then
    for colony_index := 1 to colony_count do
      set colony_id := lst_colonies.get(colony_index)
      set colony_owner := Sys_Get_Space_Object_Owner(colony_id)
      set colony_name := Sys_Get_Space_Object_Name(colony_id)
      set colony_sys_loc := Sys_Get_Space_Object_System_Location(colony_id)
      set colony_sect_loc := Sys_Get_Space_Object_Sector_Location(colony_id)
      // Is this a plagued system?
      set plague_sys_index := lst_plague_sys.indexof(colony_sys_loc)
      // Consider spreading the plague based on the event frequency
      if (plague_sys_index > 0) then
        set plague_plr := lst_plague_plr.get(plague_sys_index)
        set plague_level := lst_plague_level.get(plague_sys_index)
        // Is the colony being checked owned by the same player as the plagued planet?
        if (plague_plr = colony_owner) then
          if (Sys_Get_Planet_Plague_Level(colony_id) = 0) then
            set plague_chance := lng_Event_Frequency * 5
            // Did the plague spread?
            if (plague_chance > Sys_Get_Random_Long(1, 100)) then
              call Sys_Set_Planet_Plague_Level(colony_id, plague_level)
              // Debug output
              call Sys_Debug_Print("Events", "  - A level " + Sys_Convert_Long_To_String(plague_level) + " plague has spread to " + Sys_Empire_Get_Empire_Name(colony_owner) + "'s " + colony_name + "(" + Sys_Get_Solar_System_Name(colony_sys_loc) + " System)!")
              // Log Message
              set msg_text := "The plague in the " + Sys_Get_Solar_System_Name(colony_sys_loc) + " system has spread to our colony " + colony_name + "! It remains a level " + Sys_Convert_Long_To_String(plague_level) + " plague."
              call Sys_Add_Empire_Log_Entry(colony_owner, colony_sys_loc, colony_sect_loc, "Plague Spreading!", msg_text, "Event_PlagueBreaksOut.jpg", "LargePortrait_Event_PlagueBreaksOut.jpg", LOG_TYPE_PLANET_PLAGUED, LOG_CATEGORY_TYPE_EMPIRE_NEWS, LOG_SUB_CATEGORY_TYPE_EMPIRE_MISC, 0)
            else
              // Debug output
              call Sys_Debug_Print("Events", "    - " + colony_name + " in the " + Sys_Get_Solar_System_Name(colony_sys_loc) + " system did not get infected this turn.")
            endif
          else
            // Debug output
            call Sys_Debug_Print("Events", "    - " + colony_name + " is already plagued!")
          endif
        endif
      endif
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Execute_Blackhole_Damage
//------------------------------------------------------------------------
function Execute_Blackhole_Damage returns boolean
params
vars
  ship_count:                long
  ship_index:                long
  ship_list:                 longlist
  ship_id:                   long 
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_owner:                long
  ship_name:                 string
  ship_structure:            long
  ship_armor:                long
  ship_shields:              long
  ship_hitpoints:            long
  ship_num_weapons:          long
  ship_movement:             long
  ship_destroyed:            boolean := FALSE
  blackhole_sys_list:        longlist
  dmg_amount:                long
  dmg_type:                  string
  dmg_description:           string
  dmg_mod:                   long
  event_cause:               string
  message_title:             string
  message_text:              string
  msg_small_pic:             string
  msg_large_pic:             string
  log_type:                  long
begin

  // Get a list of all ships
  set ship_count := Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_SHIP, ship_list, TRUE, FALSE, 0)

  // Get a list of black hole system
  call Sys_Get_List_Of_Black_Holes(blackhole_sys_list)

  // Check the ship's location
  if (ship_count > 0) and (lng_Event_Frequency > 0) then
    for ship_index := 1 to ship_count do then
      set ship_id := ship_list.get(ship_index)
      set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
      set dmg_amount := 0
      // Is the ship in a black hole system?
      if (blackhole_sys_list.indexof(ship_sys_loc) > 0) then
        // Chance the ship is damaged depends on event frequency
        if (lng_Event_Frequency > Sys_Get_Random_Long(1, 50)) then
          // Get the target ship's details
          set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
          set ship_owner := Sys_Get_Space_Object_Owner(ship_id)
          set ship_name := Sys_Get_Space_Object_Name(ship_id)
          set ship_structure := Sys_Get_Space_Object_Total_Tonnage_Structure(ship_id) - Sys_Get_Space_Object_Current_Armor_Structure(ship_id)
          set ship_armor := Sys_Get_Space_Object_Current_Armor_Structure(ship_id)
          set ship_shields := Sys_Get_Space_Object_Current_Shields(ship_id)
          set ship_hitpoints := ship_structure + ship_armor + ship_shields
          set ship_num_weapons := Sys_Get_Space_Object_Number_Of_UnDamaged_Weapons(ship_id)
          set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)
          set dmg_mod := lng_Event_Severity + 1
          // Reset damage variables
          set ship_destroyed := FALSE
          set dmg_amount := 0
          // Default damage
          set event_cause := "A jet of high-energy plasma from a black hole"
          set dmg_type := "Normal"
          set dmg_description := "kT of damage"
          set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_hitpoints, 10), Sys_Divide_Long(ship_hitpoints, 6 - dmg_mod))
          // Determine the cause and amount of damage
          case Sys_Get_Random_Long(1, 10)
            1:
              if (ship_movement > 0) then
                set event_cause := "A burst of cosmic radiation from a black hole"
                set dmg_amount := Sys_Get_Random_Long(100, 100 * dmg_mod)
                set dmg_type := "Only Engines"
                set dmg_description := "kT of engine damage"
              endif
            2:
              set event_cause := "A burst of radiation from a black hole rupturing power conduits"
              set dmg_amount := Sys_Get_Random_Long(Sys_Divide_Long(ship_structure, 5), Sys_Divide_Long(ship_structure, 6 - dmg_mod))
              set dmg_type := "Skips Shields And Armor"
              set dmg_description := "kT of component damage"
            3:
              if (ship_num_weapons > 0) then
                set event_cause := "A burst of intense cosmic radiation from a black hole"
                set dmg_amount := Sys_Get_Random_Long(20, ship_num_weapons * 20 * dmg_mod)
                set dmg_type := "Only Weapons"
                set dmg_description := "kT of weapon systems damage"
              endif
            4:
              if (ship_shields > 0) then
                set event_cause := "An energetic burst of radiation burning out shield generators"
                set dmg_amount := Sys_Get_Random_Long(20, 50 * dmg_mod)
                set dmg_type := "Shield Generators Only"
                set dmg_description := "kT of shield component damage"
              endif
            5:
              if (ship_num_weapons > 0) then
                set event_cause := "A burst of cosmic radiation from a black hole"
                set dmg_amount := Sys_Get_Random_Long(100, 100 * dmg_mod)
                set dmg_type := "Only Engines"
                set dmg_description := "kT of engine damage"
              endif
          endcase
        endif
      endif

      // Was the ship destroyed?
      if (dmg_amount >= ship_hitpoints) then
        set ship_destroyed := TRUE
      endif

      // Damage the ship
      if (dmg_amount > 0) then
        call Sys_Space_Object_Take_Damage(ship_id, dmg_type, dmg_amount)

        // Log Message to owner
        set log_type := LOG_TYPE_SHIP_DAMAGED
        // Was the ship destroyed...
        if (ship_destroyed) then
          set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 44 Title")
          set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 44 Text")
          set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 44 Small Picture Filename")
          set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 44 Large Picture Filename")
        else
          // or just damaged?
          set message_title := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 43 Title")
          set message_text  := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 43 Text")
          set msg_small_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 43 Small Picture Filename")
          set msg_large_pic := Sys_Get_Datafile_Field_Value_As_String(lng_Datafile_Event_Text_ID, "Event Message 43 Large Picture Filename")
        endif

        // Replace message text
        set message_text := Sys_Replace_String(message_text, "[%EventCause%]", event_cause, TRUE, TRUE)
        set message_text := Sys_Replace_String(message_text, "[%VehicleName%]", ship_name, TRUE, TRUE)
        set message_text := Sys_Replace_String(message_text, "[%DamageAmount%]", Sys_Convert_Long_To_String(dmg_amount), TRUE, TRUE)
        set message_text := Sys_Replace_String(message_text, "[%DamageType%]", dmg_description, TRUE, TRUE)
        set message_text := Sys_Replace_String(message_text, "[%SystemName%]", Sys_Get_Solar_System_Name(ship_sys_loc), TRUE, TRUE)
        set message_text := Sys_Replace_String(message_text, "[%SectorLoc%]", Sys_Get_Sector_Coordinates(ship_sect_loc), TRUE, TRUE)
        // Create the event log
        call Give_Message_To_Players(MESSAGE_TO_OWNER, ship_owner, ship_sys_loc, ship_sect_loc, message_title, message_text, msg_small_pic, msg_large_pic, log_type)
      endif
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------